From 9d7a1b772ca5675a06bbe68df33619bbf5f1cbdb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 21 Sep 2024 11:02:23 +0200 Subject: [PATCH 01/21] one step forward --- firmware/.cargo/config.toml | 4 - firmware/app/Cargo.lock | 769 ++++++++++++++++++++++++++---------- firmware/app/Cargo.toml | 27 +- firmware/app/memory.x | 2 +- firmware/app/src/main.rs | 6 +- firmware/boot/Cargo.lock | 59 ++- firmware/boot/Cargo.toml | 11 +- firmware/boot/src/main.rs | 2 +- rust-toolchain.toml | 2 +- 9 files changed, 624 insertions(+), 258 deletions(-) diff --git a/firmware/.cargo/config.toml b/firmware/.cargo/config.toml index 535a2ad..90c4c42 100644 --- a/firmware/.cargo/config.toml +++ b/firmware/.cargo/config.toml @@ -6,10 +6,6 @@ build-std-features = ["panic_immediate_abort"] # replace nRF82832_xxAA with your chip as listed in `probe-rs-cli chip list` #runner = "probe-rs-cli run --no-location --chip nRF52832_xxAA" runner = "probe-run --chip nRF52832_xxAA" -rustflags = [ - "-C", "inline-threshold=5", # try different values here - "-C", "no-vectorize-loops", # try with and without this -] [build] target = "thumbv7em-none-eabi" diff --git a/firmware/app/Cargo.lock b/firmware/app/Cargo.lock index 5c86809..e8ee54c 100644 --- a/firmware/app/Cargo.lock +++ b/firmware/app/Cargo.lock @@ -2,21 +2,11 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -32,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "as-slice" @@ -50,9 +40,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "az" @@ -69,6 +59,28 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "bindgen" +version = "0.63.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which", +] + [[package]] name = "bit_field" version = "0.10.2" @@ -89,9 +101,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -102,6 +114,20 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "bt-hci" +version = "0.1.0" +source = "git+https://github.com/alexmoon/bt-hci.git?branch=main#b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" +dependencies = [ + "defmt", + "embassy-sync", + "embassy-time", + "embedded-io", + "embedded-io-async", + "futures-intrusive", + "heapless", +] + [[package]] name = "byte-slice-cast" version = "1.2.2" @@ -110,9 +136,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" [[package]] name = "byteorder" @@ -120,12 +146,32 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "cortex-m" version = "0.6.7" @@ -205,79 +251,44 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" -dependencies = [ - "darling_core 0.20.3", - "darling_macro 0.20.3", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_core" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.48", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.3", + "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "defmt" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" +checksum = "a99dd22262668b887121d4672af5a64b238f026099f1a2a1b322066c9ecfe9e0" dependencies = [ "bitflags 1.3.2", "defmt-macros", @@ -285,31 +296,31 @@ dependencies = [ [[package]] name = "defmt-macros" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" +checksum = "e3a9f309eff1f79b3ebdf252954d90ae440599c26c2c553fe87a2d17195f2dcb" dependencies = [ "defmt-parser", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "defmt-parser" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" +checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f" dependencies = [ "thiserror", ] [[package]] name = "defmt-rtt" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609923761264dd99ed9c7d209718cda4631c5fe84668e0f0960124cbb844c49f" +checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" dependencies = [ "critical-section", "defmt", @@ -354,18 +365,33 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" dependencies = [ "litrs", ] +[[package]] +name = "doxygen-rs" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02796cce256c1561e0ab1041c2d830ab6a6176dbeade23b5f93a2387858d0d34" +dependencies = [ + "phf", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "embassy-boot" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e917a2dba10553ab6188fdafd81e971b0441953c663842285709eaf2a5de5e5b" +checksum = "62d8a1dab79c615b36fc05d9ccaa144a7f6cec1fa6076c8b2eed628cb5f122cb" dependencies = [ "digest", "embassy-embedded-hal", @@ -377,9 +403,9 @@ dependencies = [ [[package]] name = "embassy-boot-nrf" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e96e3f3e8d38dc47c2adeb1651c177612f28990c93a14a1891d363a1403c4e" +checksum = "7f0c6b1e485d0e9201359e3a587e46eb10758202415705d2e59982924657b1bf" dependencies = [ "cfg-if", "cortex-m 0.7.7", @@ -393,9 +419,9 @@ dependencies = [ [[package]] name = "embassy-embedded-hal" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca4a9380d03e61063067b8239f67d2fa9f108ede7c46b4273804f6b79e59a1d" +checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" dependencies = [ "defmt", "embassy-futures", @@ -411,9 +437,9 @@ dependencies = [ [[package]] name = "embassy-executor" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec648daedd2143466eff4b3e8002024f9f6c1de4ab7666bb679688752624c925" +checksum = "09ed0e24bdd4a5f4ff1b72ee4f264b1d23e179ea71a77d984b5fd24877a2bbe1" dependencies = [ "cortex-m 0.7.7", "critical-section", @@ -426,14 +452,14 @@ dependencies = [ [[package]] name = "embassy-executor-macros" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab0f725ba52827eb44be22c85c52614c7402045968b26349de7f9df8421f74f" +checksum = "d4d4c0c34b32c2c653c9eecce1cefaf8539dd9a54e61deb5499254f01e2fcac2" dependencies = [ - "darling 0.20.3", + "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -444,9 +470,9 @@ checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" [[package]] name = "embassy-hal-internal" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ec47cf8bab914018d4bd2b4f0aaeb46e4f52ab1e7985df88aeef2c6eda5aed" +checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59" dependencies = [ "cortex-m 0.7.7", "critical-section", @@ -456,10 +482,11 @@ dependencies = [ [[package]] name = "embassy-nrf" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faba661a13ac3417714ef23aa191af65941586dee692dbffe76ff7d3529321b" +checksum = "a5f41f2ef4df68d3066c62667a0027b194cf6294e58afe8e6c36b8feede1e4ac" dependencies = [ + "bitflags 2.6.0", "cfg-if", "cortex-m 0.7.7", "cortex-m-rt", @@ -480,6 +507,7 @@ dependencies = [ "embedded-storage", "embedded-storage-async", "fixed", + "nrf51-pac", "nrf52805-pac", "nrf52810-pac", "nrf52811-pac", @@ -489,15 +517,16 @@ dependencies = [ "nrf52840-pac", "nrf5340-app-pac", "nrf5340-net-pac", + "nrf9120-pac", "nrf9160-pac", "rand_core", ] [[package]] name = "embassy-sync" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec" +checksum = "b3e0c49ff02ebe324faf3a8653ba91582e2d0a7fdef5bc88f449d5aa1bfcc05c" dependencies = [ "cfg-if", "critical-section", @@ -509,9 +538,9 @@ dependencies = [ [[package]] name = "embassy-time" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c844070d9f80dc66ee739299183312baee2e1cdeb6e90b4ea2af44f4676da5" +checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" dependencies = [ "cfg-if", "critical-section", @@ -600,9 +629,9 @@ dependencies = [ [[package]] name = "embedded-iconoir" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d60f645ebd83b62f6d9757084e767f72a60199f8466e22bc74274ddb6382e9" +checksum = "c52b9899b636b56d4e66834f7a90766d0bc6600c0f067d91ed0711b11fa3f5c8" dependencies = [ "bit_field", "embedded-graphics", @@ -615,6 +644,9 @@ name = "embedded-io" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +dependencies = [ + "defmt", +] [[package]] name = "embedded-io-async" @@ -622,6 +654,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" dependencies = [ + "defmt", "embedded-io", ] @@ -643,7 +676,7 @@ checksum = "4f6e621fe4c7e05b695274b722dc0a60bacd1c8696b58191baa0154713d52400" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -663,20 +696,30 @@ dependencies = [ [[package]] name = "embedded-text" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f37bb00b903818f924c57ba71ecaff99824ac480b3ba47a93de219d861403ac" +checksum = "005680edc0d075af5e02d5788ca291737bd9aba7fc404ae031cc9dfa715e5f7d" dependencies = [ "az", "embedded-graphics", "object-chain", ] +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "fixed" -version = "1.24.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c69ce7e7c0f17aa18fdd9d0de39727adb9c6281f2ad12f57cbe54ae6e76e7d" +checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" dependencies = [ "az", "bytemuck", @@ -729,6 +772,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -743,7 +796,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -800,11 +853,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "half" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -829,6 +888,15 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys", +] + [[package]] name = "hrs3300" version = "0.1.0" @@ -845,21 +913,43 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litrs" @@ -867,11 +957,27 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "micromath" @@ -879,11 +985,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mipidsi" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e2bbd372d8ae9ccd0fc6eb4d91742b971ed8149968bbc623f025506989bd30" +source = "git+https://github.com/almindor/mipidsi.git?branch=master#7ff5271e20b5d835e8ecc27537a49b5f55ec3e99" dependencies = [ "display-interface", "embedded-graphics-core", @@ -907,6 +1018,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nrf-dfu-target" version = "0.1.1" @@ -918,44 +1039,66 @@ dependencies = [ ] [[package]] -name = "nrf-softdevice" +name = "nrf-mpsl" version = "0.1.0" -source = "git+https://github.com/embassy-rs/nrf-softdevice.git?branch=master#ccba671c3f848ea7256e31549c1067e029086929" dependencies = [ "cortex-m 0.7.7", - "cortex-m-rt", "critical-section", "defmt", - "embassy-futures", + "embassy-nrf", "embassy-sync", + "embedded-io", "embedded-storage", "embedded-storage-async", - "fixed", - "futures", - "heapless", - "nrf-softdevice-macro", - "nrf-softdevice-s132", + "nrf-mpsl-sys", "nrf52832-pac", - "num_enum", ] [[package]] -name = "nrf-softdevice-macro" +name = "nrf-mpsl-sys" version = "0.1.0" -source = "git+https://github.com/embassy-rs/nrf-softdevice.git?branch=master#ccba671c3f848ea7256e31549c1067e029086929" dependencies = [ - "Inflector", - "darling 0.13.4", - "proc-macro2", - "quote", - "syn 1.0.109", - "uuid", + "bindgen", + "doxygen-rs", ] [[package]] -name = "nrf-softdevice-s132" -version = "0.1.1" -source = "git+https://github.com/embassy-rs/nrf-softdevice.git?branch=master#ccba671c3f848ea7256e31549c1067e029086929" +name = "nrf-sdc" +version = "0.1.0" +dependencies = [ + "bt-hci", + "critical-section", + "defmt", + "embassy-hal-internal", + "embassy-nrf", + "embassy-sync", + "embedded-io", + "embedded-io-async", + "nrf-mpsl", + "nrf-sdc-sys", + "rand_core", +] + +[[package]] +name = "nrf-sdc-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "doxygen-rs", + "nrf-mpsl-sys", + "winnow", +] + +[[package]] +name = "nrf51-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137f187dc6ee482e27312086bd3c3a83e1c273512782cf131a61957f72fc4219" +dependencies = [ + "cortex-m 0.7.7", + "cortex-m-rt", + "vcell", +] [[package]] name = "nrf52805-pac" @@ -1057,10 +1200,10 @@ dependencies = [ ] [[package]] -name = "nrf9160-pac" +name = "nrf9120-pac" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7344d74afb5684e00c48d175cad9619f36d629cfb0687d33b4d1bb86fba688f4" +checksum = "6c012f18dc278aa33741722d374bc84e3d2d7694e29745f0bb83e56b2d6faf9b" dependencies = [ "cortex-m 0.7.7", "cortex-m-rt", @@ -1068,39 +1211,36 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.17" +name = "nrf9160-pac" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "7344d74afb5684e00c48d175cad9619f36d629cfb0687d33b4d1bb86fba688f4" dependencies = [ - "autocfg", + "cortex-m 0.7.7", + "cortex-m-rt", + "vcell", ] [[package]] -name = "num_enum" -version = "0.7.1" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" -dependencies = [ - "num_enum_derive", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] -name = "num_enum_derive" -version = "0.7.1" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", + "autocfg", ] [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -1111,11 +1251,17 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41af26158b0f5530f7b79955006c2727cd23d0d8e7c3109dc316db0a919784dd" +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + [[package]] name = "panic-probe" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9" +checksum = "4047d9235d1423d66cc97da7d07eddb54d4f154d6c13805c6d0793956f4f25b0" dependencies = [ "cortex-m 0.7.7", "defmt", @@ -1123,15 +1269,63 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1143,7 +1337,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" name = "pinetime-flash" version = "0.1.0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "defmt", "embedded-hal 1.0.0", "embedded-storage", @@ -1151,9 +1345,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" dependencies = [ "critical-section", ] @@ -1190,22 +1384,31 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -1214,9 +1417,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "regex" -version = "1.10.2" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1226,9 +1429,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1237,9 +1440,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" @@ -1250,11 +1459,30 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" @@ -1273,30 +1501,42 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.194" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.194" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1320,9 +1560,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" @@ -1337,9 +1577,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -1348,33 +1588,34 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "time" -version = "0.3.31" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "libc", + "num-conv", "num_threads", "powerfmt", "serde", @@ -1390,13 +1631,29 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] +[[package]] +name = "trouble-host" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/trouble.git?branch=main#ecc98fc826af229dd5b8923a99dafb810ef84341" +dependencies = [ + "bt-hci", + "defmt", + "embassy-futures", + "embassy-sync", + "embassy-time", + "embedded-io-async", + "futures", + "heapless", +] + [[package]] name = "typenum" version = "1.17.0" @@ -1419,12 +1676,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "uuid" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" - [[package]] name = "vcell" version = "0.1.3" @@ -1433,20 +1684,21 @@ checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" [[package]] name = "vergen" -version = "8.2.6" +version = "8.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1290fd64cc4e7d3c9b07d7f333ce0ce0007253e32870e632624835cc80b83939" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" dependencies = [ "anyhow", + "cfg-if", "rustversion", "time", ] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -1467,6 +1719,7 @@ dependencies = [ name = "watchful" version = "0.2.5" dependencies = [ + "bt-hci", "byte-slice-cast", "cortex-m 0.7.7", "cortex-m-rt", @@ -1494,12 +1747,13 @@ dependencies = [ "hrs3300", "mipidsi", "nrf-dfu-target", - "nrf-softdevice", - "nrf-softdevice-s132", + "nrf-mpsl", + "nrf-sdc", "panic-probe", "pinetime-flash", "static_cell", "time", + "trouble-host", "vergen", "watchful-ui", ] @@ -1519,7 +1773,96 @@ dependencies = [ "u8g2-fonts", ] -[[patch.unused]] -name = "mipidsi" -version = "0.7.1" -source = "git+https://github.com/almindor/mipidsi.git?branch=master#5eb3d7e2f885c6013b0f037a61f9573ca7610d4f" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] diff --git a/firmware/app/Cargo.toml b/firmware/app/Cargo.toml index b980f6b..e2bbde6 100644 --- a/firmware/app/Cargo.toml +++ b/firmware/app/Cargo.toml @@ -9,13 +9,13 @@ resolver = "2" [dependencies] embassy-futures = { version = "0.1" } futures = { version = "0.3", default-features = false, features = ["async-await"]} -embassy-embedded-hal = { version = "0.1", default-features = false } -embassy-sync = { version = "0.5" } -embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-embedded-hal = { version = "0.2", default-features = false } +embassy-sync = { version = "0.6" } +embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-nrf = { version = "0.1", features = ["defmt", "nrf52832", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } -embassy-boot-nrf = { version = "0.2" } -embassy-boot = { version = "0.2" } +embassy-nrf = { version = "0.2", features = ["defmt", "nrf52832", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } +embassy-boot-nrf = { version = "0.3" } +embassy-boot = { version = "0.3" } embedded-io = "0.6" embedded-io-async = "0.6" embedded-storage = "0.3" @@ -26,13 +26,15 @@ watchful-ui = { version = "0.1.0", path = "../../watchful-ui", features = ["defm cst816s = "0.1.4" hrs3300 = { version = "0.1.0" } -nrf-softdevice = { version = "0.1", features = ["defmt", "nrf52832", "s132", "ble-gatt-server", "ble-gatt-client", "ble-peripheral", "critical-section-impl", "evt-max-size-256"] } -nrf-softdevice-s132 = { version = "0.1" } - defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } #defmt-brtt = { version = "0.1", features = ["async-await"] } +# +nrf-sdc = { version = "0.1.0", default-features = false, features = ["defmt", "nrf52832", "peripheral"] } +nrf-mpsl = { version = "0.1.0", default-features = false, features = ["defmt", "critical-section-impl"] } +bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } +trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } static_cell = "1.1" cortex-m = { version = "0.7.6", features = ["inline-asm"] } @@ -52,9 +54,10 @@ vergen = { version = "8", features = ["build", "git", "gitcl"] } [patch.crates-io] hrs3300 = { git = "https://github.com/lulf/hrs3300-rs.git", branch = "hal-1.0" } mipidsi = { git = "https://github.com/almindor/mipidsi.git", branch = "master" } - -nrf-softdevice = { git = "https://github.com/embassy-rs/nrf-softdevice.git", branch = "master" } -nrf-softdevice-s132 = { git = "https://github.com/embassy-rs/nrf-softdevice.git", branch = "master" } +nrf-mpsl = { git = "https://github.com/alexmoon/nrf-sdc.git", branch = "main" } +nrf-sdc = { git = "https://github.com/alexmoon/nrf-sdc.git", branch = "main" } +bt-hci = "0.1.1" +trouble-host = { git = "https://github.com/embassy-rs/trouble.git", branch = "main" } [profile.release] debug = 2 diff --git a/firmware/app/memory.x b/firmware/app/memory.x index c0f2e65..fa26fb1 100644 --- a/firmware/app/memory.x +++ b/firmware/app/memory.x @@ -9,7 +9,7 @@ MEMORY DFU : ORIGIN = 0x00000000, LENGTH = 328K - RAM : ORIGIN = 0x2000BAF0, LENGTH = 17680 + RAM : ORIGIN = 0x20000008, LENGTH = 32760 } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE); diff --git a/firmware/app/src/main.rs b/firmware/app/src/main.rs index f1bf141..2f9d110 100644 --- a/firmware/app/src/main.rs +++ b/firmware/app/src/main.rs @@ -25,14 +25,14 @@ use embassy_time::{Delay, Duration, Timer}; use heapless::Vec; use mipidsi::options::Orientation; use nrf_dfu_target::prelude::*; -use nrf_softdevice::ble::{gatt_server, peripheral, Connection}; -use nrf_softdevice::{raw, Softdevice}; +//use nrf_softdevice::ble::{gatt_server, peripheral, Connection}; +//use nrf_softdevice::{raw, Softdevice}; #[cfg(feature = "panic-probe")] use panic_probe as _; use pinetime_flash::XtFlash; use static_cell::StaticCell; -mod ble; +//mod ble; mod clock; mod device; mod state; diff --git a/firmware/boot/Cargo.lock b/firmware/boot/Cargo.lock index f9ce6f8..c553644 100644 --- a/firmware/boot/Cargo.lock +++ b/firmware/boot/Cargo.lock @@ -46,9 +46,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "embassy-boot" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e917a2dba10553ab6188fdafd81e971b0441953c663842285709eaf2a5de5e5b" +checksum = "62d8a1dab79c615b36fc05d9ccaa144a7f6cec1fa6076c8b2eed628cb5f122cb" dependencies = [ "digest", "embassy-embedded-hal", @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "embassy-boot-nrf" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e96e3f3e8d38dc47c2adeb1651c177612f28990c93a14a1891d363a1403c4e" +checksum = "7f0c6b1e485d0e9201359e3a587e46eb10758202415705d2e59982924657b1bf" dependencies = [ "cfg-if", "cortex-m", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "embassy-embedded-hal" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca4a9380d03e61063067b8239f67d2fa9f108ede7c46b4273804f6b79e59a1d" +checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" dependencies = [ "embassy-futures", "embassy-sync", @@ -249,9 +249,9 @@ checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" [[package]] name = "embassy-hal-internal" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ec47cf8bab914018d4bd2b4f0aaeb46e4f52ab1e7985df88aeef2c6eda5aed" +checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59" dependencies = [ "cortex-m", "critical-section", @@ -260,10 +260,11 @@ dependencies = [ [[package]] name = "embassy-nrf" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faba661a13ac3417714ef23aa191af65941586dee692dbffe76ff7d3529321b" +checksum = "a5f41f2ef4df68d3066c62667a0027b194cf6294e58afe8e6c36b8feede1e4ac" dependencies = [ + "bitflags 2.6.0", "cfg-if", "cortex-m", "cortex-m-rt", @@ -283,6 +284,7 @@ dependencies = [ "embedded-storage", "embedded-storage-async", "fixed", + "nrf51-pac", "nrf52805-pac", "nrf52810-pac", "nrf52811-pac", @@ -292,15 +294,16 @@ dependencies = [ "nrf52840-pac", "nrf5340-app-pac", "nrf5340-net-pac", + "nrf9120-pac", "nrf9160-pac", "rand_core", ] [[package]] name = "embassy-sync" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec" +checksum = "b3e0c49ff02ebe324faf3a8653ba91582e2d0a7fdef5bc88f449d5aa1bfcc05c" dependencies = [ "cfg-if", "critical-section", @@ -311,9 +314,9 @@ dependencies = [ [[package]] name = "embassy-time" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c844070d9f80dc66ee739299183312baee2e1cdeb6e90b4ea2af44f4676da5" +checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" dependencies = [ "cfg-if", "critical-section", @@ -505,6 +508,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f47431e7b1c13851c48a77211fac2b7b648b43a9a622f9c40debc76320b93217" +[[package]] +name = "nrf51-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137f187dc6ee482e27312086bd3c3a83e1c273512782cf131a61957f72fc4219" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + [[package]] name = "nrf52805-pac" version = "0.12.2" @@ -604,6 +618,17 @@ dependencies = [ "vcell", ] +[[package]] +name = "nrf9120-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c012f18dc278aa33741722d374bc84e3d2d7694e29745f0bb83e56b2d6faf9b" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + [[package]] name = "nrf9160-pac" version = "0.12.2" @@ -650,7 +675,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" name = "pinetime-flash" version = "0.1.0" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.6.0", "embedded-hal 1.0.0", "embedded-storage", ] diff --git a/firmware/boot/Cargo.toml b/firmware/boot/Cargo.toml index 7a7518e..3b7a7c7 100644 --- a/firmware/boot/Cargo.toml +++ b/firmware/boot/Cargo.toml @@ -7,11 +7,11 @@ resolver = "2" [dependencies] embassy-futures = { version = "0.1", default-features = false } -embassy-sync = { version = "0.5", default-features = false } -embassy-nrf = { version = "0.1", default-features = false, features = ["rt", "nrf52832", "time", "gpiote", "time-driver-rtc1"] } -embassy-embedded-hal = { version = "0.1", default-features = false } -embassy-boot = { version = "0.2", default-features = false } -embassy-boot-nrf = { version = "0.2", default-features = false, features = ["softdevice"] } +embassy-sync = { version = "0.6", default-features = false } +embassy-nrf = { version = "0.2", default-features = false, features = ["rt", "nrf52832", "time", "gpiote", "time-driver-rtc1"] } +embassy-embedded-hal = { version = "0.2", default-features = false } +embassy-boot = { version = "0.3", default-features = false } +embassy-boot-nrf = { version = "0.3", default-features = false, features = ["softdevice"] } embedded-io = "0.6" embedded-storage-async = "0.4" embedded-storage = "0.3" @@ -33,4 +33,3 @@ codegen-units = 1 incremental = false lto = "fat" opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. - diff --git a/firmware/boot/src/main.rs b/firmware/boot/src/main.rs index 61dfb57..4ce58cd 100644 --- a/firmware/boot/src/main.rs +++ b/firmware/boot/src/main.rs @@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs { SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler; }); -type ExternalFlash<'a, 'b> = XtFlash, Output<'b, P0_05>>>; +type ExternalFlash<'a, 'b> = XtFlash, Output<'b>>>; #[entry] fn main() -> ! { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c85fb6f..0d9e283 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2023-12-20" +channel = "nightly-2024-07-16" components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] targets = [ "thumbv7em-none-eabi", From 59abb04f1f8378757e34244e5a6f3c883ef735bf Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 29 Nov 2024 23:27:35 +0100 Subject: [PATCH 02/21] Update --- firmware/{app => }/Cargo.lock | 445 ++++++---------- firmware/{app => }/Cargo.toml | 27 +- firmware/boot/Cargo.lock | 879 ------------------------------- firmware/boot/Cargo.toml | 35 -- firmware/boot/build.rs | 35 -- firmware/boot/memory.x | 35 -- firmware/boot/src/main.rs | 128 ----- firmware/{app => }/build.rs | 0 firmware/{app => }/memory.x | 0 firmware/{app => }/src/ble.rs | 132 ++++- firmware/{app => }/src/clock.rs | 0 firmware/{app => }/src/device.rs | 23 +- firmware/{app => }/src/fmt.rs | 1 + firmware/{app => }/src/main.rs | 169 +++--- firmware/{app => }/src/state.rs | 0 pinetime-flash/src/fmt.rs | 1 + 16 files changed, 392 insertions(+), 1518 deletions(-) rename firmware/{app => }/Cargo.lock (85%) rename firmware/{app => }/Cargo.toml (53%) delete mode 100644 firmware/boot/Cargo.lock delete mode 100644 firmware/boot/Cargo.toml delete mode 100644 firmware/boot/build.rs delete mode 100644 firmware/boot/memory.x delete mode 100644 firmware/boot/src/main.rs rename firmware/{app => }/build.rs (100%) rename firmware/{app => }/memory.x (100%) rename firmware/{app => }/src/ble.rs (60%) rename firmware/{app => }/src/clock.rs (100%) rename firmware/{app => }/src/device.rs (84%) rename firmware/{app => }/src/fmt.rs (99%) rename firmware/{app => }/src/main.rs (73%) rename firmware/{app => }/src/state.rs (100%) diff --git a/firmware/app/Cargo.lock b/firmware/Cargo.lock similarity index 85% rename from firmware/app/Cargo.lock rename to firmware/Cargo.lock index e8ee54c..e6a2000 100644 --- a/firmware/app/Cargo.lock +++ b/firmware/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -61,24 +71,22 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.63.0" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "cexpr", "clang-sys", - "lazy_static", - "lazycell", + "itertools", "log", - "peeking_take_while", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 1.0.109", - "which", + "syn 2.0.89", ] [[package]] @@ -116,8 +124,9 @@ dependencies = [ [[package]] name = "bt-hci" -version = "0.1.0" -source = "git+https://github.com/alexmoon/bt-hci.git?branch=main#b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69e2db053409c36c45a403da58072b8bf75bdc962746c0a12df9dec0fce92d2" dependencies = [ "defmt", "embassy-sync", @@ -126,6 +135,7 @@ dependencies = [ "embedded-io-async", "futures-intrusive", "heapless", + "uuid", ] [[package]] @@ -270,7 +280,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -281,7 +291,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -304,7 +314,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -313,7 +323,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f" dependencies = [ - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -374,9 +384,9 @@ dependencies = [ [[package]] name = "doxygen-rs" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02796cce256c1561e0ab1041c2d830ab6a6176dbeade23b5f93a2387858d0d34" +checksum = "415b6ec780d34dcf624666747194393603d0373b7141eef01d12ee58881507d9" dependencies = [ "phf", ] @@ -390,8 +400,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "embassy-boot" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d8a1dab79c615b36fc05d9ccaa144a7f6cec1fa6076c8b2eed628cb5f122cb" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "digest", "embassy-embedded-hal", @@ -404,8 +413,7 @@ dependencies = [ [[package]] name = "embassy-boot-nrf" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f0c6b1e485d0e9201359e3a587e46eb10758202415705d2e59982924657b1bf" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "cfg-if", "cortex-m 0.7.7", @@ -420,8 +428,7 @@ dependencies = [ [[package]] name = "embassy-embedded-hal" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "defmt", "embassy-futures", @@ -459,20 +466,27 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] name = "embassy-futures" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" [[package]] name = "embassy-hal-internal" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59" +dependencies = [ + "num-traits", +] + +[[package]] +name = "embassy-hal-internal" +version = "0.2.0" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "cortex-m 0.7.7", "critical-section", @@ -483,8 +497,7 @@ dependencies = [ [[package]] name = "embassy-nrf" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f41f2ef4df68d3066c62667a0027b194cf6294e58afe8e6c36b8feede1e4ac" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -494,7 +507,7 @@ dependencies = [ "defmt", "document-features", "embassy-embedded-hal", - "embassy-hal-internal", + "embassy-hal-internal 0.2.0 (git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f)", "embassy-sync", "embassy-time", "embassy-time-driver", @@ -507,31 +520,20 @@ dependencies = [ "embedded-storage", "embedded-storage-async", "fixed", - "nrf51-pac", - "nrf52805-pac", - "nrf52810-pac", - "nrf52811-pac", - "nrf52820-pac", - "nrf52832-pac", - "nrf52833-pac", - "nrf52840-pac", - "nrf5340-app-pac", - "nrf5340-net-pac", - "nrf9120-pac", - "nrf9160-pac", + "nrf-pac", "rand_core", ] [[package]] name = "embassy-sync" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e0c49ff02ebe324faf3a8653ba91582e2d0a7fdef5bc88f449d5aa1bfcc05c" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "cfg-if", "critical-section", "defmt", "embedded-io-async", + "futures-sink", "futures-util", "heapless", ] @@ -539,8 +541,7 @@ dependencies = [ [[package]] name = "embassy-time" version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "cfg-if", "critical-section", @@ -558,8 +559,7 @@ dependencies = [ [[package]] name = "embassy-time-driver" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "document-features", ] @@ -567,14 +567,12 @@ dependencies = [ [[package]] name = "embassy-time-queue-driver" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" [[package]] name = "embassy-usb-driver" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc247028eae04174b6635104a35b1ed336aabef4654f5e87a8f32327d231970" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "defmt", ] @@ -676,7 +674,7 @@ checksum = "4f6e621fe4c7e05b695274b722dc0a60bacd1c8696b58191baa0154713d52400" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -705,16 +703,6 @@ dependencies = [ "object-chain", ] -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys", -] - [[package]] name = "fixed" version = "1.28.0" @@ -796,7 +784,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -888,15 +876,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys", -] - [[package]] name = "hrs3300" version = "0.1.0" @@ -911,6 +890,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -923,12 +911,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.155" @@ -945,12 +927,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "litrs" version = "0.4.1" @@ -994,7 +970,8 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mipidsi" version = "0.8.0" -source = "git+https://github.com/almindor/mipidsi.git?branch=master#7ff5271e20b5d835e8ecc27537a49b5f55ec3e99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e2bbd372d8ae9ccd0fc6eb4d91742b971ed8149968bbc623f025506989bd30" dependencies = [ "display-interface", "embedded-graphics-core", @@ -1041,6 +1018,7 @@ dependencies = [ [[package]] name = "nrf-mpsl" version = "0.1.0" +source = "git+https://github.com/alexmoon/nrf-sdc.git?rev=9696ce04fd417dc5c448edbafab3fef23f2f34cd#9696ce04fd417dc5c448edbafab3fef23f2f34cd" dependencies = [ "cortex-m 0.7.7", "critical-section", @@ -1051,25 +1029,35 @@ dependencies = [ "embedded-storage", "embedded-storage-async", "nrf-mpsl-sys", - "nrf52832-pac", ] [[package]] name = "nrf-mpsl-sys" version = "0.1.0" +source = "git+https://github.com/alexmoon/nrf-sdc.git?rev=9696ce04fd417dc5c448edbafab3fef23f2f34cd#9696ce04fd417dc5c448edbafab3fef23f2f34cd" dependencies = [ "bindgen", "doxygen-rs", ] +[[package]] +name = "nrf-pac" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/nrf-pac?rev=12e2461859acb0bfea9b2ef5cd73f1283c139ac0#12e2461859acb0bfea9b2ef5cd73f1283c139ac0" +dependencies = [ + "cortex-m 0.7.7", + "cortex-m-rt", +] + [[package]] name = "nrf-sdc" version = "0.1.0" +source = "git+https://github.com/alexmoon/nrf-sdc.git?rev=9696ce04fd417dc5c448edbafab3fef23f2f34cd#9696ce04fd417dc5c448edbafab3fef23f2f34cd" dependencies = [ "bt-hci", "critical-section", "defmt", - "embassy-hal-internal", + "embassy-hal-internal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "embassy-nrf", "embassy-sync", "embedded-io", @@ -1082,6 +1070,7 @@ dependencies = [ [[package]] name = "nrf-sdc-sys" version = "0.1.0" +source = "git+https://github.com/alexmoon/nrf-sdc.git?rev=9696ce04fd417dc5c448edbafab3fef23f2f34cd#9696ce04fd417dc5c448edbafab3fef23f2f34cd" dependencies = [ "bindgen", "doxygen-rs", @@ -1090,150 +1079,38 @@ dependencies = [ ] [[package]] -name = "nrf51-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "137f187dc6ee482e27312086bd3c3a83e1c273512782cf131a61957f72fc4219" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52805-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2da657648039d59f4de6bc31b948dd3a5d03b32529a4d5d19d9e2dd9d4bfa6c" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52810-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26b12d5af17a9f4bb9a06ca9a1f814bca3d67bc8715b23f8dc230b09a227666" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52811-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4179b2a7ed0b2fd5e109d0fab9b4fc55b3936b2a4916a9306d22e5bc8dc1fd8f" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52820-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4791cff995e6419a5ad1aebc3b3c9539d79125ca85eb5bfd2cff9b470b81071" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52832-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0242b685c9c15648fb803e155628f42ace457478b2cb930868f40cae2db925e0" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52833-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10e1358255b360cdc816dd7b6ef81be8c8499c0998277e5249bed222bd0f5241" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52840-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf5340-app-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c88824573cd150fe9f27c1a48cea31a8cb24d3322df488875775143618c087a" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf5340-net-pac" -version = "0.12.2" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c03e44df22fe5888109fe42e523162c7059adf4d30860f4f73ecc8b1fc16fe" -dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] -name = "nrf9120-pac" -version = "0.12.2" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c012f18dc278aa33741722d374bc84e3d2d7694e29745f0bb83e56b2d6faf9b" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", + "autocfg", ] [[package]] -name = "nrf9160-pac" -version = "0.12.2" +name = "num_enum" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7344d74afb5684e00c48d175cad9619f36d629cfb0687d33b4d1bb86fba688f4" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "cortex-m 0.7.7", - "cortex-m-rt", - "vcell", + "num_enum_derive", ] [[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" +name = "num_enum_derive" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "autocfg", + "proc-macro2", + "quote", + "syn 2.0.89", ] [[package]] @@ -1251,12 +1128,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41af26158b0f5530f7b79955006c2727cd23d0d8e7c3109dc316db0a919784dd" -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - [[package]] name = "panic-probe" version = "0.3.2" @@ -1273,12 +1144,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "phf" version = "0.11.2" @@ -1309,7 +1174,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -1358,6 +1223,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn 2.0.89", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1384,9 +1259,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1459,19 +1334,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - [[package]] name = "rustversion" version = "1.0.17" @@ -1516,7 +1378,7 @@ checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", ] [[package]] @@ -1558,6 +1420,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "static_cell" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89b0684884a883431282db1e4343f34afc2ff6996fe1f4a1664519b66e14c1e" +dependencies = [ + "portable-atomic", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1577,9 +1448,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -1592,7 +1463,16 @@ version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.63", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] @@ -1603,7 +1483,18 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.89", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", ] [[package]] @@ -1642,16 +1533,34 @@ dependencies = [ [[package]] name = "trouble-host" version = "0.1.0" -source = "git+https://github.com/embassy-rs/trouble.git?branch=main#ecc98fc826af229dd5b8923a99dafb810ef84341" +source = "git+https://github.com/embassy-rs/trouble.git?rev=b470edeff6eeb76655ee69d503f3776a166a7375#b470edeff6eeb76655ee69d503f3776a166a7375" dependencies = [ "bt-hci", "defmt", "embassy-futures", "embassy-sync", "embassy-time", + "embedded-io", "embedded-io-async", "futures", "heapless", + "num_enum", + "static_cell 2.1.0", + "thiserror 2.0.3", + "trouble-host-macros", +] + +[[package]] +name = "trouble-host-macros" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/trouble.git?rev=b470edeff6eeb76655ee69d503f3776a166a7375#b470edeff6eeb76655ee69d503f3776a166a7375" +dependencies = [ + "Inflector", + "darling", + "proc-macro2", + "quote", + "syn 2.0.89", + "uuid", ] [[package]] @@ -1676,6 +1585,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" + [[package]] name = "vcell" version = "0.1.3" @@ -1751,7 +1666,7 @@ dependencies = [ "nrf-sdc", "panic-probe", "pinetime-flash", - "static_cell", + "static_cell 1.3.0", "time", "trouble-host", "vergen", @@ -1773,27 +1688,6 @@ dependencies = [ "u8g2-fonts", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -1860,9 +1754,14 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] + +[[patch.unused]] +name = "embassy-executor" +version = "0.6.3" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" diff --git a/firmware/app/Cargo.toml b/firmware/Cargo.toml similarity index 53% rename from firmware/app/Cargo.toml rename to firmware/Cargo.toml index e2bbde6..5ff18d8 100644 --- a/firmware/app/Cargo.toml +++ b/firmware/Cargo.toml @@ -11,7 +11,7 @@ embassy-futures = { version = "0.1" } futures = { version = "0.3", default-features = false, features = ["async-await"]} embassy-embedded-hal = { version = "0.2", default-features = false } embassy-sync = { version = "0.6" } -embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-nrf = { version = "0.2", features = ["defmt", "nrf52832", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } embassy-boot-nrf = { version = "0.3" } @@ -21,8 +21,8 @@ embedded-io-async = "0.6" embedded-storage = "0.3" embedded-hal = "1.0" nrf-dfu-target = { version = "0.1.1", features = ["defmt"] } -pinetime-flash = { version = "0.1.0", path = "../../pinetime-flash", features = ["defmt"] } -watchful-ui = { version = "0.1.0", path = "../../watchful-ui", features = ["defmt"] } +pinetime-flash = { version = "0.1.0", path = "../pinetime-flash", features = ["defmt"] } +watchful-ui = { version = "0.1.0", path = "../watchful-ui", features = ["defmt"] } cst816s = "0.1.4" hrs3300 = { version = "0.1.0" } @@ -33,7 +33,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } # nrf-sdc = { version = "0.1.0", default-features = false, features = ["defmt", "nrf52832", "peripheral"] } nrf-mpsl = { version = "0.1.0", default-features = false, features = ["defmt", "critical-section-impl"] } -bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } +bt-hci = { version = "0.1.2", default-features = false, features = ["defmt"] } trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } static_cell = "1.1" @@ -53,11 +53,20 @@ vergen = { version = "8", features = ["build", "git", "gitcl"] } [patch.crates-io] hrs3300 = { git = "https://github.com/lulf/hrs3300-rs.git", branch = "hal-1.0" } -mipidsi = { git = "https://github.com/almindor/mipidsi.git", branch = "master" } -nrf-mpsl = { git = "https://github.com/alexmoon/nrf-sdc.git", branch = "main" } -nrf-sdc = { git = "https://github.com/alexmoon/nrf-sdc.git", branch = "main" } -bt-hci = "0.1.1" -trouble-host = { git = "https://github.com/embassy-rs/trouble.git", branch = "main" } +nrf-mpsl = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "9696ce04fd417dc5c448edbafab3fef23f2f34cd" } +nrf-sdc = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "9696ce04fd417dc5c448edbafab3fef23f2f34cd" } +trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "b470edeff6eeb76655ee69d503f3776a166a7375"} + +embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-boot = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } +embassy-boot-nrf = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } [profile.release] debug = 2 diff --git a/firmware/boot/Cargo.lock b/firmware/boot/Cargo.lock deleted file mode 100644 index c553644..0000000 --- a/firmware/boot/Cargo.lock +++ /dev/null @@ -1,879 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "az" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bytemuck" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal", - "bitfield", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "defmt" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" -dependencies = [ - "bitflags 1.3.2", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" -dependencies = [ - "defmt-parser", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.28", -] - -[[package]] -name = "defmt-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609923761264dd99ed9c7d209718cda4631c5fe84668e0f0960124cbb844c49f" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "document-features" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" -dependencies = [ - "litrs", -] - -[[package]] -name = "embassy-boot" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d8a1dab79c615b36fc05d9ccaa144a7f6cec1fa6076c8b2eed628cb5f122cb" -dependencies = [ - "digest", - "embassy-embedded-hal", - "embassy-sync", - "embedded-storage", - "embedded-storage-async", - "signature", -] - -[[package]] -name = "embassy-boot-nrf" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f0c6b1e485d0e9201359e3a587e46eb10758202415705d2e59982924657b1bf" -dependencies = [ - "cfg-if", - "cortex-m", - "cortex-m-rt", - "embassy-boot", - "embassy-nrf", - "embassy-sync", - "embedded-storage", - "embedded-storage-async", - "nrf-softdevice-mbr", -] - -[[package]] -name = "embassy-embedded-hal" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" -dependencies = [ - "embassy-futures", - "embassy-sync", - "embassy-time", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-storage", - "embedded-storage-async", - "nb 1.1.0", -] - -[[package]] -name = "embassy-futures" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" - -[[package]] -name = "embassy-hal-internal" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59" -dependencies = [ - "cortex-m", - "critical-section", - "num-traits", -] - -[[package]] -name = "embassy-nrf" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f41f2ef4df68d3066c62667a0027b194cf6294e58afe8e6c36b8feede1e4ac" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cortex-m", - "cortex-m-rt", - "critical-section", - "document-features", - "embassy-embedded-hal", - "embassy-hal-internal", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embassy-usb-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-io", - "embedded-io-async", - "embedded-storage", - "embedded-storage-async", - "fixed", - "nrf51-pac", - "nrf52805-pac", - "nrf52810-pac", - "nrf52811-pac", - "nrf52820-pac", - "nrf52832-pac", - "nrf52833-pac", - "nrf52840-pac", - "nrf5340-app-pac", - "nrf5340-net-pac", - "nrf9120-pac", - "nrf9160-pac", - "rand_core", -] - -[[package]] -name = "embassy-sync" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e0c49ff02ebe324faf3a8653ba91582e2d0a7fdef5bc88f449d5aa1bfcc05c" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-util", - "heapless", -] - -[[package]] -name = "embassy-time" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" -dependencies = [ - "cfg-if", - "critical-section", - "document-features", - "embassy-time-driver", - "embassy-time-queue-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "futures-util", - "heapless", -] - -[[package]] -name = "embassy-time-driver" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24" -dependencies = [ - "document-features", -] - -[[package]] -name = "embassy-time-queue-driver" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0" - -[[package]] -name = "embassy-usb-driver" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc247028eae04174b6635104a35b1ed336aabef4654f5e87a8f32327d231970" - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-io-async" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" -dependencies = [ - "embedded-io", -] - -[[package]] -name = "embedded-storage" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" - -[[package]] -name = "embedded-storage-async" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" -dependencies = [ - "embedded-storage", -] - -[[package]] -name = "fixed" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9" -dependencies = [ - "az", - "bytemuck", - "half", - "typenum", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "half" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nrf-softdevice-mbr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47431e7b1c13851c48a77211fac2b7b648b43a9a622f9c40debc76320b93217" - -[[package]] -name = "nrf51-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "137f187dc6ee482e27312086bd3c3a83e1c273512782cf131a61957f72fc4219" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52805-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2da657648039d59f4de6bc31b948dd3a5d03b32529a4d5d19d9e2dd9d4bfa6c" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52810-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26b12d5af17a9f4bb9a06ca9a1f814bca3d67bc8715b23f8dc230b09a227666" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52811-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4179b2a7ed0b2fd5e109d0fab9b4fc55b3936b2a4916a9306d22e5bc8dc1fd8f" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52820-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4791cff995e6419a5ad1aebc3b3c9539d79125ca85eb5bfd2cff9b470b81071" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52832-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0242b685c9c15648fb803e155628f42ace457478b2cb930868f40cae2db925e0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52833-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10e1358255b360cdc816dd7b6ef81be8c8499c0998277e5249bed222bd0f5241" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52840-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf5340-app-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c88824573cd150fe9f27c1a48cea31a8cb24d3322df488875775143618c087a" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf5340-net-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c03e44df22fe5888109fe42e523162c7059adf4d30860f4f73ecc8b1fc16fe" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf9120-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c012f18dc278aa33741722d374bc84e3d2d7694e29745f0bb83e56b2d6faf9b" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf9160-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7344d74afb5684e00c48d175cad9619f36d629cfb0687d33b4d1bb86fba688f4" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "panic-probe" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9" -dependencies = [ - "cortex-m", - "defmt", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pinetime-flash" -version = "0.1.0" -dependencies = [ - "bitflags 2.6.0", - "embedded-hal 1.0.0", - "embedded-storage", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_cell" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cd323fc21eb534f903ee78d781d622099f9716c5b408ed23bcf39f8f1651c0" -dependencies = [ - "atomic-polyfill", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.28", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" -dependencies = [ - "vcell", -] - -[[package]] -name = "watchful-bootloader" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "defmt", - "defmt-rtt", - "embassy-boot", - "embassy-boot-nrf", - "embassy-embedded-hal", - "embassy-futures", - "embassy-nrf", - "embassy-sync", - "embedded-hal 1.0.0", - "embedded-io", - "embedded-storage", - "embedded-storage-async", - "nrf-softdevice-mbr", - "panic-probe", - "pinetime-flash", - "static_cell", -] diff --git a/firmware/boot/Cargo.toml b/firmware/boot/Cargo.toml deleted file mode 100644 index 3b7a7c7..0000000 --- a/firmware/boot/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -edition = "2021" -name = "watchful-bootloader" -version = "0.1.0" -license = "MIT OR Apache-2.0" -resolver = "2" - -[dependencies] -embassy-futures = { version = "0.1", default-features = false } -embassy-sync = { version = "0.6", default-features = false } -embassy-nrf = { version = "0.2", default-features = false, features = ["rt", "nrf52832", "time", "gpiote", "time-driver-rtc1"] } -embassy-embedded-hal = { version = "0.2", default-features = false } -embassy-boot = { version = "0.3", default-features = false } -embassy-boot-nrf = { version = "0.3", default-features = false, features = ["softdevice"] } -embedded-io = "0.6" -embedded-storage-async = "0.4" -embedded-storage = "0.3" -embedded-hal = "1.0" -nrf-softdevice-mbr = { version = "0.2" } -pinetime-flash = { version = "0.1.0", path = "../../pinetime-flash" } - -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } - -static_cell = "1.1" -cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -cortex-m-rt = "0.7.0" - -[profile.release] -debug = 2 -codegen-units = 1 -incremental = false -lto = "fat" -opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. diff --git a/firmware/boot/build.rs b/firmware/boot/build.rs deleted file mode 100644 index 30691aa..0000000 --- a/firmware/boot/build.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! This build script copies the `memory.x` file from the crate root into -//! a directory where the linker can always find it at build time. -//! For many projects this is optional, as the linker always searches the -//! project root directory -- wherever `Cargo.toml` is. However, if you -//! are using a workspace or have a more complicated build setup, this -//! build script becomes required. Additionally, by requesting that -//! Cargo re-run the build script whenever `memory.x` is changed, -//! updating `memory.x` ensures a rebuild of the application with the -//! new memory settings. - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); - - println!("cargo:rustc-link-arg-bins=--nmagic"); - println!("cargo:rustc-link-arg-bins=-Tlink.x"); - println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); -} diff --git a/firmware/boot/memory.x b/firmware/boot/memory.x deleted file mode 100644 index ffe5528..0000000 --- a/firmware/boot/memory.x +++ /dev/null @@ -1,35 +0,0 @@ -MEMORY -{ - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - MBR : ORIGIN = 0x00000000, LENGTH = 4K - SOFTDEVICE : ORIGIN = 0x00001000, LENGTH = 148K - ACTIVE : ORIGIN = 0x00026000, LENGTH = 324K - FLASH : ORIGIN = 0x00077000, LENGTH = 32K - BOOTLOADER_STATE : ORIGIN = 0x0007F000, LENGTH = 4K - - DFU : ORIGIN = 0x00000000, LENGTH = 328K - - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 0xfff8 - /* NOTE: Disable when building reloader */ - uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4 -} - -__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); -__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); - -__bootloader_active_start = ORIGIN(ACTIVE); -__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE); - -__bootloader_dfu_start = ORIGIN(DFU); -__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); - -__bootloader_start = ORIGIN(FLASH); - -/* NOTE: Disable when building reloader */ -SECTIONS -{ - .uicr_bootloader_start_address : - { - LONG(__bootloader_start) - } > uicr_bootloader_start_address -} diff --git a/firmware/boot/src/main.rs b/firmware/boot/src/main.rs deleted file mode 100644 index 4ce58cd..0000000 --- a/firmware/boot/src/main.rs +++ /dev/null @@ -1,128 +0,0 @@ -#![no_std] -#![no_main] - -use core::cell::RefCell; - -use cortex_m_rt::{entry, exception}; -use defmt_rtt as _; -use embassy_boot_nrf::*; -use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::nvmc::Nvmc; -use embassy_nrf::peripherals::{self, P0_05, TWISPI0}; -use embassy_nrf::{bind_interrupts, spim, wdt}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::blocking_mutex::Mutex; -#[cfg(feature = "panic-probe")] -use panic_probe as _; -use pinetime_flash::*; - -bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler; -}); - -type ExternalFlash<'a, 'b> = XtFlash, Output<'b>>>; - -#[entry] -fn main() -> ! { - let p = embassy_nrf::init(Default::default()); - - // Uncomment this if you are debugging the bootloader with debugger/RTT attached, - // as it prevents a hard fault when accessing flash 'too early' after boot. - // for i in 0..10000000 { - // cortex_m::asm::nop(); - // } - - let mut wdt_config = wdt::Config::default(); - wdt_config.timeout_ticks = 32768 * 20; // timeout seconds - wdt_config.run_during_sleep = true; - wdt_config.run_during_debug_halt = false; - - let internal_flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); - let internal_flash = Mutex::new(RefCell::new(internal_flash)); - - let mut default_config = spim::Config::default(); - default_config.frequency = spim::Frequency::M8; - default_config.mode = spim::MODE_3; - - let active_offset; - let bl: BootLoader = { - let spim = spim::Spim::new(p.TWISPI0, Irqs, p.P0_02, p.P0_04, p.P0_03, default_config); - let bus = Mutex::new(RefCell::new(spim)); - let flash_cs = Output::new(p.P0_05, Level::High, OutputDrive::Standard); - let flash_spi = SpiDevice::new(&bus, flash_cs); - let external_flash = XtFlash::new(flash_spi); - let external_flash = external_flash.unwrap(); - let external_flash = Mutex::new(RefCell::new(external_flash)); - - let config = create_flash_config(&internal_flash, &external_flash); - active_offset = config.active.offset(); - - BootLoader::prepare(config) - }; - - unsafe { bl.load(active_offset) } -} - -pub fn create_flash_config<'a, 'b, 'c>( - internal: &'a Mutex>>>, - external: &'a Mutex>>, -) -> BootLoaderConfig< - BlockingPartition<'a, NoopRawMutex, WatchdogFlash>>, - BlockingPartition<'a, NoopRawMutex, ExternalFlash<'b, 'c>>, - BlockingPartition<'a, NoopRawMutex, WatchdogFlash>>, -> { - extern "C" { - static __bootloader_state_start: u32; - static __bootloader_state_end: u32; - static __bootloader_active_start: u32; - static __bootloader_active_end: u32; - static __bootloader_dfu_start: u32; - static __bootloader_dfu_end: u32; - } - - let active = unsafe { - let start = &__bootloader_active_start as *const u32 as u32; - let end = &__bootloader_active_end as *const u32 as u32; - // trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end); - - BlockingPartition::new(internal, start, end - start) - }; - let dfu = unsafe { - let start = &__bootloader_dfu_start as *const u32 as u32; - let end = &__bootloader_dfu_end as *const u32 as u32; - // trace!("DFU: 0x{:x} - 0x{:x}", start, end); - - BlockingPartition::new(external, start, end - start) - }; - let state = unsafe { - let start = &__bootloader_state_start as *const u32 as u32; - let end = &__bootloader_state_end as *const u32 as u32; - // trace!("STATE: 0x{:x} - 0x{:x}", start, end); - - BlockingPartition::new(internal, start, end - start) - }; - - BootLoaderConfig { active, dfu, state } -} - -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] -unsafe extern "C" fn HardFault() { - cortex_m::peripheral::SCB::sys_reset(); -} - -#[exception] -unsafe fn DefaultHandler(_: i16) -> ! { - const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; - - panic!("DefaultHandler #{:?}", irqn); -} - -#[cfg(not(feature = "panic-probe"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - cortex_m::asm::udf(); -} diff --git a/firmware/app/build.rs b/firmware/build.rs similarity index 100% rename from firmware/app/build.rs rename to firmware/build.rs diff --git a/firmware/app/memory.x b/firmware/memory.x similarity index 100% rename from firmware/app/memory.x rename to firmware/memory.x diff --git a/firmware/app/src/ble.rs b/firmware/src/ble.rs similarity index 60% rename from firmware/app/src/ble.rs rename to firmware/src/ble.rs index 7034620..c2df6c1 100644 --- a/firmware/app/src/ble.rs +++ b/firmware/src/ble.rs @@ -1,17 +1,20 @@ -use defmt::{info, warn}; +use defmt::{info, unwrap, warn}; +use embassy_executor::Spawner; use embedded_storage::nor_flash::NorFlash; use heapless::Vec; -use nrf_dfu_target::prelude::*; -use nrf_softdevice::ble::gatt_server::NotifyValueError; -use nrf_softdevice::ble::{gatt_client, Connection}; +use nrf_dfu_target::prelude::{DfuStatus, DfuTarget}; +use static_cell::StaticCell; +use trouble_host::gatt::GattEvent; +use trouble_host::prelude::*; pub const MTU: usize = 120; // Aligned to 4 bytes + 3 bytes for header pub const ATT_MTU: usize = MTU + 3; type Target = DfuTarget<256>; +type NrfController = nrf_sdc::SoftdeviceController<'static>; -#[nrf_softdevice::gatt_service(uuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")] +#[gatt_service(uuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")] pub struct NrfUartService { #[characteristic(uuid = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E", write)] rx: Vec, @@ -20,6 +23,7 @@ pub struct NrfUartService { tx: Vec, } +/* impl NrfUartService { fn handle(&self, _connection: &mut ConnectionHandle, event: NrfUartServiceEvent) { match event { @@ -30,8 +34,9 @@ impl NrfUartService { } } } +*/ -#[nrf_softdevice::gatt_service(uuid = "FE59")] +#[gatt_service(uuid = "FE59")] pub struct NrfDfuService { #[characteristic(uuid = "8EC90001-F315-4F60-9FB8-838830DAEA50", write, notify)] control: Vec, @@ -43,6 +48,7 @@ pub struct NrfDfuService { packet: Vec, } +/* pub struct ConnectionHandle { pub connection: Connection, pub notify_control: bool, @@ -86,7 +92,7 @@ impl NrfDfuService { if let Ok((request, _)) = DfuRequest::decode(&data) { return Some(self.process(target, dfu, connection, request, |conn, response| { if conn.notify_control { - self.control_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; + // TODO self.control_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; } Ok(()) })); @@ -99,7 +105,7 @@ impl NrfDfuService { let request = DfuRequest::Write { data: &data[..] }; return Some(self.process(target, dfu, connection, request, |conn, response| { if conn.notify_control { - self.control_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; + // TODO self.control_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; } // if conn.notify_packet { // self.packet_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; @@ -114,14 +120,16 @@ impl NrfDfuService { None } } +*/ -#[nrf_softdevice::gatt_server] +#[gatt_server] pub struct PineTimeServer { dfu: NrfDfuService, uart: NrfUartService, } -#[nrf_softdevice::gatt_client(uuid = "1805")] +/* +#[gatt_client(uuid = "1805")] struct CurrentTimeServiceClient { #[characteristic(uuid = "2a2b", write, read, notify)] current_time: Vec, @@ -168,21 +176,119 @@ impl CurrentTimeServiceClient { Err(gatt_client::ReadError::Truncated) } } +*/ -impl PineTimeServer { +impl PineTimeServer<'_, '_, NrfController> { pub fn handle( &self, target: &mut Target, dfu: &mut DFU, - conn: &mut ConnectionHandle, - event: PineTimeServerEvent, + conn: &mut Connection<'static>, + event: GattEvent, ) -> Option { + todo!() + /* match event { PineTimeServerEvent::Dfu(event) => self.dfu.handle(target, dfu, conn, event), PineTimeServerEvent::Uart(event) => { self.uart.handle(conn, event); None } + }*/ + } +} + +/// Size of L2CAP packets (ATT MTU is this - 4) +const L2CAP_MTU: usize = 251; +const CONNECTIONS_MAX: usize = 2; +const L2CAP_CHANNELS_MAX: usize = 2; // Signal + att +type BleResources = HostResources; +static RESOURCES: StaticCell = StaticCell::new(); + +fn ble_addr() -> Address { + unsafe { + let ficr = embassy_nrf::pac::FICR; + let high = u64::from((ficr.deviceaddr(1).read() & 0x0000ffff) | 0x0000c000); + let addr = high << 32 | u64::from(ficr.deviceaddr(0).read()); + Address::random(unwrap!(addr.to_le_bytes()[..6].try_into())) + } +} + +pub fn start(spawner: Spawner, controller: NrfController) { + let resources = RESOURCES.init(BleResources::new(PacketQos::None)); + let (stack, mut peripheral, _, runner) = trouble_host::new(controller, resources) + .set_random_address(ble_addr()) + .build(); + + let gatt = unwrap!(PineTimeServer::new_with_config( + stack, + GapConfig::Peripheral(PeripheralConfig { + name: "Watchful", + appearance: &appearance::power_device::GENERIC_POWER_DEVICE, + }), + )); + static SERVER: StaticCell> = StaticCell::new(); + let server = SERVER.init(gatt); + + spawner.must_spawn(ble_task(runner)); + spawner.must_spawn(gatt_task(server)); + spawner.must_spawn(advertise_task(peripheral, server)); +} + +#[embassy_executor::task] +async fn ble_task(mut runner: Runner<'static, NrfController>) { + unwrap!(runner.run().await); +} + +#[embassy_executor::task] +async fn gatt_task(server: &'static PineTimeServer<'_, '_, NrfController>) { + unwrap!(server.run().await); +} + +#[embassy_executor::task] +async fn advertise_task( + mut peripheral: Peripheral<'static, NrfController>, + server: &'static PineTimeServer<'_, '_, NrfController>, +) { + let mut advertiser_data = [0; 31]; + unwrap!(AdStructure::encode_slice( + &[ + AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), + AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]), + AdStructure::CompleteLocalName(b"Watchful"), + ], + &mut advertiser_data[..], + )); + let mut advertiser = unwrap!( + peripheral + .advertise( + &Default::default(), + Advertisement::ConnectableScannableUndirected { + adv_data: &advertiser_data[..], + scan_data: &[], + }, + ) + .await + ); + loop { + match advertiser.accept().await { + Ok(conn) => process(conn, server).await, + Err(e) => { + warn!("Error advertising: {:?}", e); + } + } + } +} + +async fn process(connection: Connection<'static>, server: &'static PineTimeServer<'_, '_, NrfController>) { + loop { + match connection.next().await { + ConnectionEvent::Disconnected { reason } => { + break; + } + ConnectionEvent::Gatt { event, .. } => { + todo!() + } } } } diff --git a/firmware/app/src/clock.rs b/firmware/src/clock.rs similarity index 100% rename from firmware/app/src/clock.rs rename to firmware/src/clock.rs diff --git a/firmware/app/src/device.rs b/firmware/src/device.rs similarity index 84% rename from firmware/app/src/device.rs rename to firmware/src/device.rs index 501cd2e..5bc28eb 100644 --- a/firmware/app/src/device.rs +++ b/firmware/src/device.rs @@ -1,9 +1,9 @@ -use embassy_boot_nrf::FirmwareState; use display_interface_spi::SPIInterface; +use embassy_boot_nrf::FirmwareState; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_futures::select::{select, Either}; -use embassy_nrf::gpio::{AnyPin, Input, Output}; +use embassy_nrf::gpio::{Input, Output}; use embassy_nrf::peripherals::{P0_10, P0_18, P0_25, P0_26, P0_28, TWISPI0, TWISPI1}; use embassy_nrf::spim::Spim; use embassy_nrf::{saadc, twim}; @@ -13,13 +13,12 @@ use mipidsi::models::ST7789; use crate::clock::Clock; -pub type Touchpad<'a> = - cst816s::CST816S>, Input<'a, P0_28>, Output<'a, P0_10>>; +pub type Touchpad<'a> = cst816s::CST816S>, Input<'a>, Output<'a>>; pub type Hrs<'a> = hrs3300::Hrs3300>>; pub type Display<'a> = mipidsi::Display< - SPIInterface, Output<'a, P0_25>>, Output<'a, P0_18>>, + SPIInterface, Output<'a>>, Output<'a>>, ST7789, - Output<'a, P0_26>, + Output<'a>, >; pub struct Device<'a> { @@ -35,11 +34,11 @@ pub struct Device<'a> { impl<'a> Device<'a> {} pub struct Button { - pin: Input<'static, AnyPin>, + pin: Input<'static>, } impl Button { - pub fn new(pin: Input<'static, AnyPin>) -> Self { + pub fn new(pin: Input<'static>) -> Self { Self { pin } } pub async fn wait(&mut self) { @@ -58,12 +57,12 @@ impl Button { } pub struct Battery<'a> { - charging: Input<'a, AnyPin>, + charging: Input<'a>, adc: saadc::Saadc<'a, 1>, } impl<'a> Battery<'a> { - pub fn new(adc: saadc::Saadc<'a, 1>, charging: Input<'a, AnyPin>) -> Self { + pub fn new(adc: saadc::Saadc<'a, 1>, charging: Input<'a>) -> Self { Self { adc, charging } } pub async fn measure(&mut self) -> u32 { @@ -81,11 +80,11 @@ impl<'a> Battery<'a> { pub struct Screen<'a> { display: Display<'a>, - backlight: Output<'a, AnyPin>, + backlight: Output<'a>, } impl<'a> Screen<'a> { - pub fn new(display: Display<'a>, backlight: Output<'a, AnyPin>) -> Self { + pub fn new(display: Display<'a>, backlight: Output<'a>) -> Self { Self { display, backlight } } diff --git a/firmware/app/src/fmt.rs b/firmware/src/fmt.rs similarity index 99% rename from firmware/app/src/fmt.rs rename to firmware/src/fmt.rs index 0669708..3b8e8d5 100644 --- a/firmware/app/src/fmt.rs +++ b/firmware/src/fmt.rs @@ -201,6 +201,7 @@ pub struct NoneError; pub trait Try { type Ok; type Error; + #[allow(dead_code)] fn into_result(self) -> Result; } diff --git a/firmware/app/src/main.rs b/firmware/src/main.rs similarity index 73% rename from firmware/app/src/main.rs rename to firmware/src/main.rs index 2f9d110..6233b73 100644 --- a/firmware/app/src/main.rs +++ b/firmware/src/main.rs @@ -3,7 +3,7 @@ use core::cell::RefCell; -use defmt::info; +use defmt::{info, unwrap}; use defmt_rtt as _; use display_interface_spi::SPIInterface; use embassy_boot_nrf::{AlignedBuffer, FirmwareState}; @@ -13,11 +13,11 @@ use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin, Pull}; use embassy_nrf::interrupt::Priority; -use embassy_nrf::peripherals::{P0_05, TWISPI0, TWISPI1}; +use embassy_nrf::peripherals::{P0_05, RNG, TWISPI0, TWISPI1}; use embassy_nrf::spim::Spim; use embassy_nrf::spis::MODE_3; use embassy_nrf::twim::Twim; -use embassy_nrf::{bind_interrupts, pac, peripherals, saadc, spim, twim}; +use embassy_nrf::{bind_interrupts, pac, peripherals, rng, saadc, spim, twim}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex as BMutex; use embassy_sync::mutex::Mutex; @@ -25,14 +25,13 @@ use embassy_time::{Delay, Duration, Timer}; use heapless::Vec; use mipidsi::options::Orientation; use nrf_dfu_target::prelude::*; -//use nrf_softdevice::ble::{gatt_server, peripheral, Connection}; -//use nrf_softdevice::{raw, Softdevice}; +use nrf_sdc::{self as sdc, mpsl}; #[cfg(feature = "panic-probe")] use panic_probe as _; use pinetime_flash::XtFlash; use static_cell::StaticCell; -//mod ble; +mod ble; mod clock; mod device; mod state; @@ -41,16 +40,22 @@ use crate::device::{Battery, Button, Device, Hrs, Screen}; use crate::state::WatchState; bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler; - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => twim::InterruptHandler; + TWISPI0 => spim::InterruptHandler; + TWISPI1 => twim::InterruptHandler; SAADC => saadc::InterruptHandler; + RNG => rng::InterruptHandler; + EGU0_SWI0 => mpsl::LowPrioInterruptHandler; + CLOCK_POWER => mpsl::ClockInterruptHandler; + RADIO => mpsl::HighPrioInterruptHandler; + TIMER0 => mpsl::HighPrioInterruptHandler; + RTC0 => mpsl::HighPrioInterruptHandler; }); static CLOCK: clock::Clock = clock::Clock::new(); -type ExternalFlash = XtFlash, Output<'static, P0_05>>>; +type ExternalFlash = XtFlash, Output<'static>>>; -type InternalFlash = nrf_softdevice::Flash; +type InternalFlash = mpsl::Flash<'static>; type StatePartition<'a> = Partition<'a, NoopRawMutex, InternalFlash>; type DfuPartition<'a> = BlockingPartition<'a, NoopRawMutex, ExternalFlash>; @@ -66,6 +71,24 @@ fn panic(_info: &PanicInfo) -> ! { cortex_m::peripheral::SCB::sys_reset(); } +#[embassy_executor::task] +async fn mpsl_task(mpsl: &'static mpsl::MultiprotocolServiceLayer<'static>) -> ! { + mpsl.run().await +} + +fn build_sdc<'d, const N: usize>( + p: sdc::Peripherals<'d>, + rng: &'d mut rng::Rng, + mpsl: &'d mpsl::MultiprotocolServiceLayer, + mem: &'d mut sdc::Mem, +) -> Result, sdc::Error> { + sdc::Builder::new()? + .support_adv()? + .support_peripheral()? + .peripheral_count(1)? + .build(p, rng, mpsl, mem) +} + #[embassy_executor::main] async fn main(s: Spawner) { let mut config = embassy_nrf::config::Config::default(); @@ -73,13 +96,39 @@ async fn main(s: Spawner) { config.time_interrupt_priority = Priority::P2; let p = embassy_nrf::init(config); - let sd = enable_softdevice("Watchful Embassy"); + let mpsl_p = mpsl::Peripherals::new(p.RTC0, p.TIMER0, p.TEMP, p.PPI_CH19, p.PPI_CH30, p.PPI_CH31); + let lfclk_cfg = mpsl::raw::mpsl_clock_lfclk_cfg_t { + source: mpsl::raw::MPSL_CLOCK_LF_SRC_RC as u8, + rc_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_CTIV as u8, + rc_temp_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_TEMP_CTIV as u8, + accuracy_ppm: mpsl::raw::MPSL_DEFAULT_CLOCK_ACCURACY_PPM as u16, + skip_wait_lfclk_started: mpsl::raw::MPSL_DEFAULT_SKIP_WAIT_LFCLK_STARTED != 0, + }; + static MPSL: StaticCell = StaticCell::new(); + static SESSION_MEM: StaticCell> = StaticCell::new(); + let mpsl = MPSL.init(unwrap!(mpsl::MultiprotocolServiceLayer::with_timeslots( + mpsl_p, + Irqs, + lfclk_cfg, + SESSION_MEM.init(mpsl::SessionMem::new()) + ))); + s.must_spawn(mpsl_task(&*mpsl)); + + let sdc_p = sdc::Peripherals::new( + p.PPI_CH17, p.PPI_CH18, p.PPI_CH20, p.PPI_CH21, p.PPI_CH22, p.PPI_CH23, p.PPI_CH24, p.PPI_CH25, p.PPI_CH26, + p.PPI_CH27, p.PPI_CH28, p.PPI_CH29, + ); - static GATT: StaticCell = StaticCell::new(); - let server = GATT.init(ble::PineTimeServer::new(sd).unwrap()); + let rng = rng::Rng::new(p.RNG, Irqs); + + static SDC_MEM: StaticCell> = StaticCell::new(); + let sdc_mem = SDC_MEM.init(sdc::Mem::new()); + + static RNG: StaticCell> = StaticCell::new(); + let rng = RNG.init(rng); + + let sdc = unwrap!(build_sdc(sdc_p, rng, mpsl, sdc_mem)); - s.spawn(softdevice_task(sd)).unwrap(); - s.spawn(watchdog_task()).unwrap(); s.spawn(clock(&CLOCK)).unwrap(); // Battery measurement @@ -130,7 +179,7 @@ async fn main(s: Spawner) { static EXTERNAL_FLASH: StaticCell>> = StaticCell::new(); let external_flash = EXTERNAL_FLASH.init(BMutex::new(RefCell::new(xt_flash))); - let internal_flash = nrf_softdevice::Flash::take(sd); + let internal_flash = mpsl::Flash::take(mpsl, p.NVMC); static INTERNAL_FLASH: StaticCell> = StaticCell::new(); let internal_flash = INTERNAL_FLASH.init(Mutex::new(internal_flash)); @@ -139,10 +188,10 @@ async fn main(s: Spawner) { let mut magic = AlignedBuffer([0; 4]); let fw: FirmwareState<'_, _> = FirmwareState::new(dfu_config.state(), &mut magic.0); - // Display - s.spawn(advertiser_task(s, sd, server, dfu_config.clone(), "Watchful Embassy")) - .unwrap(); + // BLE + ble::start(s, sdc); + // Display let backlight = Output::new(p.P0_22.degrade(), Level::Low, OutputDrive::Standard); // Medium backlight let rst = Output::new(p.P0_26, Level::Low, OutputDrive::Standard); let display_cs = Output::new(p.P0_25, Level::High, OutputDrive::Standard); // Keep low while driving display @@ -180,6 +229,7 @@ async fn main(s: Spawner) { } } +/* pub async fn gatt_server_task(conn: Connection, server: &'static ble::PineTimeServer, dfu_config: DfuConfig<'static>) { let p = unsafe { pac::Peripherals::steal() }; let part = p.FICR.info.part.read().part().bits(); @@ -219,6 +269,7 @@ pub async fn gatt_server_task(conn: Connection, server: &'static ble::PineTimeSe .await; info!("Disconnected"); } +*/ #[embassy_executor::task] pub async fn finish_dfu(config: DfuConfig<'static>) { @@ -235,86 +286,6 @@ pub async fn finish_dfu(config: DfuConfig<'static>) { } } -#[embassy_executor::task] -pub async fn advertiser_task( - _spawner: Spawner, - sd: &'static Softdevice, - server: &'static ble::PineTimeServer, - dfu_config: DfuConfig<'static>, - name: &'static str, -) { - let mut adv_data: Vec = Vec::new(); - #[rustfmt::skip] - adv_data.extend_from_slice(&[ - 0x02, 0x01, raw::BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE as u8, - 0x03, 0x03, 0xFE, 0x59, - (1 + name.len() as u8), 0x09]).unwrap(); - - adv_data.extend_from_slice(name.as_bytes()).ok().unwrap(); - - #[rustfmt::skip] - let scan_data = &[ - 0x03, 0x03, 0x0A, 0x18, - ]; - - loop { - let config = peripheral::Config::default(); - let adv = peripheral::ConnectableAdvertisement::ScannableUndirected { - adv_data: &adv_data[..], - scan_data, - }; - info!("Advertising"); - let conn = peripheral::advertise_connectable(sd, adv, &config).await.unwrap(); - - info!("Connection established"); - Timer::after(Duration::from_secs(1)).await; - info!("Syncing time"); - ble::sync_time(&conn, &CLOCK).await; - - gatt_server_task(conn, server, dfu_config.clone()).await; - } -} - -fn enable_softdevice(name: &'static str) -> &'static mut Softdevice { - let config = nrf_softdevice::Config { - clock: Some(raw::nrf_clock_lf_cfg_t { - source: raw::NRF_CLOCK_LF_SRC_RC as u8, - rc_ctiv: 4, - rc_temp_ctiv: 2, - accuracy: 7, - }), - conn_gap: Some(raw::ble_gap_conn_cfg_t { - conn_count: 2, - event_length: 24, - }), - conn_gatt: Some(raw::ble_gatt_conn_cfg_t { - att_mtu: crate::ble::ATT_MTU as u16, - }), - gatts_attr_tab_size: Some(raw::ble_gatts_cfg_attr_tab_size_t { attr_tab_size: 32768 }), - gap_role_count: Some(raw::ble_gap_cfg_role_count_t { - adv_set_count: 1, - periph_role_count: 3, - central_role_count: 1, - central_sec_count: 1, - _bitfield_1: Default::default(), - }), - gap_device_name: Some(raw::ble_gap_cfg_device_name_t { - p_value: name.as_ptr() as *const u8 as _, - current_len: name.len() as u16, - max_len: name.len() as u16, - write_perm: unsafe { core::mem::zeroed() }, - _bitfield_1: raw::ble_gap_cfg_device_name_t::new_bitfield_1(raw::BLE_GATTS_VLOC_STACK as u8), - }), - ..Default::default() - }; - Softdevice::enable(&config) -} - -#[embassy_executor::task] -async fn softdevice_task(sd: &'static Softdevice) { - sd.run().await; -} - // Keeps our system alive #[embassy_executor::task] async fn watchdog_task() { diff --git a/firmware/app/src/state.rs b/firmware/src/state.rs similarity index 100% rename from firmware/app/src/state.rs rename to firmware/src/state.rs diff --git a/pinetime-flash/src/fmt.rs b/pinetime-flash/src/fmt.rs index 0669708..3b8e8d5 100644 --- a/pinetime-flash/src/fmt.rs +++ b/pinetime-flash/src/fmt.rs @@ -201,6 +201,7 @@ pub struct NoneError; pub trait Try { type Ok; type Error; + #[allow(dead_code)] fn into_result(self) -> Result; } From 26dcb01030610d4091ef04f42fce8860fe911c58 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 29 Nov 2024 23:30:07 +0100 Subject: [PATCH 03/21] Fix gha --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6f8790b..e516528 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v3 - name: Build run: | - for p in firmware/boot firmware/app pinetime-flash watchful-ui; do + for p in firmware pinetime-flash watchful-ui; do pushd $p; cargo build --release; popd; @@ -38,7 +38,7 @@ jobs: - name: Build release artifacts run: | - cd firmware/app + cd firmware cargo build --release cargo objcopy --release -- -O binary watchful.bin cargo objcopy --release -- -O ihex watchful.hex From e76944ba5a851e994acc91f82ee5c896bfb4b94b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 30 Nov 2024 00:16:50 +0100 Subject: [PATCH 04/21] Add dfu support --- firmware/src/ble.rs | 198 ++++++++++++++++++++--------------------- firmware/src/device.rs | 2 +- firmware/src/main.rs | 67 +------------- 3 files changed, 102 insertions(+), 165 deletions(-) diff --git a/firmware/src/ble.rs b/firmware/src/ble.rs index c2df6c1..4a7e564 100644 --- a/firmware/src/ble.rs +++ b/firmware/src/ble.rs @@ -2,11 +2,14 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embedded_storage::nor_flash::NorFlash; use heapless::Vec; -use nrf_dfu_target::prelude::{DfuStatus, DfuTarget}; +use nrf_dfu_target::prelude::{DfuRequest, DfuStatus, DfuTarget, FirmwareInfo, FirmwareType, HardwareInfo}; use static_cell::StaticCell; +use trouble_host::attribute::Characteristic; use trouble_host::gatt::GattEvent; use trouble_host::prelude::*; +use crate::DfuConfig; + pub const MTU: usize = 120; // Aligned to 4 bytes + 3 bytes for header pub const ATT_MTU: usize = MTU + 3; @@ -48,84 +51,10 @@ pub struct NrfDfuService { packet: Vec, } -/* -pub struct ConnectionHandle { - pub connection: Connection, - pub notify_control: bool, - pub notify_packet: bool, -} - -impl NrfDfuService { - fn process Result<(), NotifyValueError>>( - &self, - target: &mut Target, - dfu: &mut DFU, - conn: &mut ConnectionHandle, - request: DfuRequest<'_>, - notify: F, - ) -> DfuStatus { - let (response, status) = target.process(request, dfu); - let mut buf: [u8; 32] = [0; 32]; - match response.encode(&mut buf[..]) { - Ok(len) => match notify(&conn, &buf[..len]) { - Ok(_) => {} - Err(e) => { - warn!("Error sending notification: {:?}", e); - } - }, - Err(e) => { - warn!("Error encoding DFU response: {:?}", e); - } - } - status - } - - fn handle( - &self, - target: &mut Target, - dfu: &mut DFU, - connection: &mut ConnectionHandle, - event: NrfDfuServiceEvent, - ) -> Option { - match event { - NrfDfuServiceEvent::ControlWrite(data) => { - if let Ok((request, _)) = DfuRequest::decode(&data) { - return Some(self.process(target, dfu, connection, request, |conn, response| { - if conn.notify_control { - // TODO self.control_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; - } - Ok(()) - })); - } - } - NrfDfuServiceEvent::ControlCccdWrite { notifications } => { - connection.notify_control = notifications; - } - NrfDfuServiceEvent::PacketWrite(data) => { - let request = DfuRequest::Write { data: &data[..] }; - return Some(self.process(target, dfu, connection, request, |conn, response| { - if conn.notify_control { - // TODO self.control_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; - } - // if conn.notify_packet { - // self.packet_notify(&conn.connection, &Vec::from_slice(response).unwrap())?; - // } - Ok(()) - })); - } - NrfDfuServiceEvent::PacketCccdWrite { notifications } => { - connection.notify_packet = notifications; - } - } - None - } -} -*/ - #[gatt_server] pub struct PineTimeServer { dfu: NrfDfuService, - uart: NrfUartService, + // uart: NrfUartService, } /* @@ -179,22 +108,47 @@ impl CurrentTimeServiceClient { */ impl PineTimeServer<'_, '_, NrfController> { - pub fn handle( + pub async fn handle( &self, target: &mut Target, dfu: &mut DFU, - conn: &mut Connection<'static>, - event: GattEvent, + connection: Connection<'static>, + handle: u16, ) -> Option { - todo!() - /* - match event { - PineTimeServerEvent::Dfu(event) => self.dfu.handle(target, dfu, conn, event), - PineTimeServerEvent::Uart(event) => { - self.uart.handle(conn, event); + if handle == self.dfu.control.handle { + let data = unwrap!(self.get(&self.dfu.control)); + if let Ok((request, _)) = DfuRequest::decode(&data) { + let (response, status) = target.process(request, dfu); + let mut buf: [u8; 32] = [0; 32]; + if let Ok(len) = response.encode(&mut buf[..]) { + let response = Vec::from_slice(&buf[..len]).unwrap(); + if let Err(e) = self.notify(&self.dfu.control, &connection, &response).await { + warn!("Error notifying control: {:?}", e); + } + } + Some(status) + } else { None } - }*/ + } else if handle == self.dfu.packet.handle { + let data = unwrap!(self.get(&self.dfu.packet)); + let request = DfuRequest::Write { data: &data[..] }; + let (response, status) = target.process(request, dfu); + let mut buf: [u8; 32] = [0; 32]; + if let Ok(len) = response.encode(&mut buf[..]) { + let response = Vec::from_slice(&buf[..len]).unwrap(); + if let Err(e) = self.notify(&self.dfu.control, &connection, &response).await { + warn!("Error notifying control: {:?}", e); + } + + if let Err(e) = self.notify(&self.dfu.packet, &connection, &response).await { + warn!("Error notifying packet: {:?}", e); + } + } + Some(status) + } else { + None + } } } @@ -206,17 +160,15 @@ type BleResources = HostResources = StaticCell::new(); fn ble_addr() -> Address { - unsafe { - let ficr = embassy_nrf::pac::FICR; - let high = u64::from((ficr.deviceaddr(1).read() & 0x0000ffff) | 0x0000c000); - let addr = high << 32 | u64::from(ficr.deviceaddr(0).read()); - Address::random(unwrap!(addr.to_le_bytes()[..6].try_into())) - } + let ficr = embassy_nrf::pac::FICR; + let high = u64::from((ficr.deviceaddr(1).read() & 0x0000ffff) | 0x0000c000); + let addr = high << 32 | u64::from(ficr.deviceaddr(0).read()); + Address::random(unwrap!(addr.to_le_bytes()[..6].try_into())) } -pub fn start(spawner: Spawner, controller: NrfController) { +pub fn start(spawner: Spawner, controller: NrfController, dfu_config: DfuConfig<'static>) { let resources = RESOURCES.init(BleResources::new(PacketQos::None)); - let (stack, mut peripheral, _, runner) = trouble_host::new(controller, resources) + let (stack, peripheral, _, runner) = trouble_host::new(controller, resources) .set_random_address(ble_addr()) .build(); @@ -232,7 +184,7 @@ pub fn start(spawner: Spawner, controller: NrfController) { spawner.must_spawn(ble_task(runner)); spawner.must_spawn(gatt_task(server)); - spawner.must_spawn(advertise_task(peripheral, server)); + spawner.must_spawn(advertise_task(peripheral, server, dfu_config)); } #[embassy_executor::task] @@ -249,6 +201,7 @@ async fn gatt_task(server: &'static PineTimeServer<'_, '_, NrfController>) { async fn advertise_task( mut peripheral: Peripheral<'static, NrfController>, server: &'static PineTimeServer<'_, '_, NrfController>, + mut dfu_config: DfuConfig<'static>, ) { let mut advertiser_data = [0; 31]; unwrap!(AdStructure::encode_slice( @@ -272,7 +225,7 @@ async fn advertise_task( ); loop { match advertiser.accept().await { - Ok(conn) => process(conn, server).await, + Ok(conn) => process(conn, server, &mut dfu_config).await, Err(e) => { warn!("Error advertising: {:?}", e); } @@ -280,15 +233,58 @@ async fn advertise_task( } } -async fn process(connection: Connection<'static>, server: &'static PineTimeServer<'_, '_, NrfController>) { +async fn process( + connection: Connection<'static>, + server: &'static PineTimeServer<'_, '_, NrfController>, + dfu_config: &mut DfuConfig<'static>, +) { + let ficr = embassy_nrf::pac::FICR; + let part = ficr.info().part().read().part().to_bits(); + let variant = ficr.info().variant().read().variant().to_bits(); + + let hw_info = HardwareInfo { + part, + variant, + rom_size: 0, + ram_size: 0, + rom_page_size: 0, + }; + + let fw_info = FirmwareInfo { + ftype: FirmwareType::Application, + version: 1, + addr: 0, + len: 0, + }; + + let mut dfu = dfu_config.dfu(); + let mut target = DfuTarget::new(dfu.size(), fw_info, hw_info); + loop { match connection.next().await { - ConnectionEvent::Disconnected { reason } => { + ConnectionEvent::Disconnected { reason: _ } => { break; } - ConnectionEvent::Gatt { event, .. } => { - todo!() - } + ConnectionEvent::Gatt { event, connection } => match event { + GattEvent::Write { value_handle } => { + if let Some(DfuStatus::DoneReset) = + server.handle(&mut target, &mut dfu, connection, value_handle).await + { + let mut magic = crate::AlignedBuffer([0; 4]); + let mut state = embassy_boot::FirmwareState::new(dfu_config.state(), &mut magic.0); + match state.mark_updated().await { + Ok(_) => { + info!("Firmware updated, resetting"); + cortex_m::peripheral::SCB::sys_reset(); + } + Err(e) => { + panic!("Error marking firmware updated: {:?}", e); + } + } + } + } + _ => {} + }, } } } diff --git a/firmware/src/device.rs b/firmware/src/device.rs index 5bc28eb..18ae8ec 100644 --- a/firmware/src/device.rs +++ b/firmware/src/device.rs @@ -4,7 +4,7 @@ use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_futures::select::{select, Either}; use embassy_nrf::gpio::{Input, Output}; -use embassy_nrf::peripherals::{P0_10, P0_18, P0_25, P0_26, P0_28, TWISPI0, TWISPI1}; +use embassy_nrf::peripherals::{TWISPI0, TWISPI1}; use embassy_nrf::spim::Spim; use embassy_nrf::{saadc, twim}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 6233b73..fc2ca3e 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -3,7 +3,7 @@ use core::cell::RefCell; -use defmt::{info, unwrap}; +use defmt::unwrap; use defmt_rtt as _; use display_interface_spi::SPIInterface; use embassy_boot_nrf::{AlignedBuffer, FirmwareState}; @@ -13,18 +13,16 @@ use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin, Pull}; use embassy_nrf::interrupt::Priority; -use embassy_nrf::peripherals::{P0_05, RNG, TWISPI0, TWISPI1}; +use embassy_nrf::peripherals::{RNG, TWISPI0, TWISPI1}; use embassy_nrf::spim::Spim; use embassy_nrf::spis::MODE_3; use embassy_nrf::twim::Twim; -use embassy_nrf::{bind_interrupts, pac, peripherals, rng, saadc, spim, twim}; +use embassy_nrf::{bind_interrupts, peripherals, rng, saadc, spim, twim}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex as BMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Delay, Duration, Timer}; -use heapless::Vec; use mipidsi::options::Orientation; -use nrf_dfu_target::prelude::*; use nrf_sdc::{self as sdc, mpsl}; #[cfg(feature = "panic-probe")] use panic_probe as _; @@ -189,7 +187,7 @@ async fn main(s: Spawner) { let fw: FirmwareState<'_, _> = FirmwareState::new(dfu_config.state(), &mut magic.0); // BLE - ble::start(s, sdc); + ble::start(s, sdc, dfu_config); // Display let backlight = Output::new(p.P0_22.degrade(), Level::Low, OutputDrive::Standard); // Medium backlight @@ -229,63 +227,6 @@ async fn main(s: Spawner) { } } -/* -pub async fn gatt_server_task(conn: Connection, server: &'static ble::PineTimeServer, dfu_config: DfuConfig<'static>) { - let p = unsafe { pac::Peripherals::steal() }; - let part = p.FICR.info.part.read().part().bits(); - let variant = p.FICR.info.variant.read().variant().bits(); - - let hw_info = HardwareInfo { - part, - variant, - rom_size: 0, - ram_size: 0, - rom_page_size: 0, - }; - - let fw_info = FirmwareInfo { - ftype: FirmwareType::Application, - version: 1, - addr: 0, - len: 0, - }; - - let mut conn_handle = ble::ConnectionHandle { - connection: conn.clone(), - notify_control: false, - notify_packet: false, - }; - - info!("Running GATT server"); - let mut dfu = dfu_config.dfu(); - let mut target = DfuTarget::new(dfu.size(), fw_info, hw_info); - let spawner = Spawner::for_current_executor().await; - - let _ = gatt_server::run(&conn, server, |e| { - if let Some(DfuStatus::DoneReset) = server.handle(&mut target, &mut dfu, &mut conn_handle, e) { - let _ = spawner.spawn(finish_dfu(dfu_config.clone())); - } - }) - .await; - info!("Disconnected"); -} -*/ - -#[embassy_executor::task] -pub async fn finish_dfu(config: DfuConfig<'static>) { - let mut magic = AlignedBuffer([0; 4]); - let mut state = FirmwareState::new(config.state(), &mut magic.0); - match state.mark_updated().await { - Ok(_) => { - info!("Firmware updated, resetting"); - cortex_m::peripheral::SCB::sys_reset(); - } - Err(e) => { - panic!("Error marking firmware updated: {:?}", e); - } - } -} - // Keeps our system alive #[embassy_executor::task] async fn watchdog_task() { From 0e80f35f78bff30d695c005294afdfdb45635d63 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 30 Nov 2024 00:34:31 +0100 Subject: [PATCH 05/21] Prepare for switch to mcuboot No DFU yet --- .github/workflows/ci.yaml | 11 +- firmware/Cargo.lock | 65 --- firmware/Cargo.toml | 4 - firmware/memory.x | 15 +- firmware/src/ble.rs | 23 +- firmware/src/device.rs | 2 - firmware/src/main.rs | 19 +- firmware/src/state.rs | 8 +- tools/mcuboot/README | 1 + tools/mcuboot/assemble.py | 131 +++++ tools/mcuboot/flash.sh | 18 + tools/mcuboot/gdb-boot.sh | 27 + tools/mcuboot/imgtool.nix | 30 ++ tools/mcuboot/imgtool.py | 20 + tools/mcuboot/imgtool/__init__.py | 15 + tools/mcuboot/imgtool/boot_record.py | 50 ++ tools/mcuboot/imgtool/image.py | 552 +++++++++++++++++++++ tools/mcuboot/imgtool/keys/__init__.py | 94 ++++ tools/mcuboot/imgtool/keys/ecdsa.py | 157 ++++++ tools/mcuboot/imgtool/keys/ecdsa_test.py | 99 ++++ tools/mcuboot/imgtool/keys/ed25519.py | 105 ++++ tools/mcuboot/imgtool/keys/ed25519_test.py | 103 ++++ tools/mcuboot/imgtool/keys/general.py | 45 ++ tools/mcuboot/imgtool/keys/rsa.py | 163 ++++++ tools/mcuboot/imgtool/keys/rsa_test.py | 115 +++++ tools/mcuboot/imgtool/keys/x25519.py | 107 ++++ tools/mcuboot/imgtool/main.py | 352 +++++++++++++ tools/mcuboot/imgtool/version.py | 53 ++ tools/mcuboot/jgdb.sh | 6 + tools/mcuboot/jl.sh | 5 + tools/mcuboot/mcubin.bt | 135 +++++ tools/mcuboot/requirements.txt | 4 + tools/mcuboot/setup.py | 29 ++ 33 files changed, 2448 insertions(+), 115 deletions(-) create mode 100644 tools/mcuboot/README create mode 100644 tools/mcuboot/assemble.py create mode 100644 tools/mcuboot/flash.sh create mode 100644 tools/mcuboot/gdb-boot.sh create mode 100644 tools/mcuboot/imgtool.nix create mode 100755 tools/mcuboot/imgtool.py create mode 100644 tools/mcuboot/imgtool/__init__.py create mode 100644 tools/mcuboot/imgtool/boot_record.py create mode 100644 tools/mcuboot/imgtool/image.py create mode 100644 tools/mcuboot/imgtool/keys/__init__.py create mode 100644 tools/mcuboot/imgtool/keys/ecdsa.py create mode 100644 tools/mcuboot/imgtool/keys/ecdsa_test.py create mode 100644 tools/mcuboot/imgtool/keys/ed25519.py create mode 100644 tools/mcuboot/imgtool/keys/ed25519_test.py create mode 100644 tools/mcuboot/imgtool/keys/general.py create mode 100644 tools/mcuboot/imgtool/keys/rsa.py create mode 100644 tools/mcuboot/imgtool/keys/rsa_test.py create mode 100644 tools/mcuboot/imgtool/keys/x25519.py create mode 100644 tools/mcuboot/imgtool/main.py create mode 100644 tools/mcuboot/imgtool/version.py create mode 100644 tools/mcuboot/jgdb.sh create mode 100644 tools/mcuboot/jl.sh create mode 100644 tools/mcuboot/mcubin.bt create mode 100644 tools/mcuboot/requirements.txt create mode 100644 tools/mcuboot/setup.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e516528..c8ff012 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,6 +34,7 @@ jobs: - name: Install prerequisites run: | pip3 install adafruit-nrfutil + pip3 install -r tools/mcuboot/requirements.txt cargo install cargo-binutils - name: Build release artifacts @@ -41,8 +42,8 @@ jobs: cd firmware cargo build --release cargo objcopy --release -- -O binary watchful.bin - cargo objcopy --release -- -O ihex watchful.hex - adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application watchful.bin watchful-dfu.zip + ../tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header watchful.bin watchful-image.bin + adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application watchful-image.bin watchful-dfu.zip - name: Upload binary uses: actions/upload-artifact@v3 @@ -56,6 +57,12 @@ jobs: name: watchful.hex path: firmware/app/watchful.hex + - name: Upload Mcuboot image + uses: actions/upload-artifact@v3 + with: + name: watchful-image.bin + path: firmware/app/watchful-image.bin + - name: Upload DFU bundle uses: actions/upload-artifact@v3 with: diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index e6a2000..993f919 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -113,15 +113,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array 0.14.7", -] - [[package]] name = "bt-hci" version = "0.1.2" @@ -239,16 +230,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array 0.14.7", - "typenum", -] - [[package]] name = "cst816s" version = "0.1.4" @@ -345,16 +326,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - [[package]] name = "display-interface" version = "0.5.0" @@ -397,34 +368,6 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -[[package]] -name = "embassy-boot" -version = "0.3.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" -dependencies = [ - "digest", - "embassy-embedded-hal", - "embassy-sync", - "embedded-storage", - "embedded-storage-async", - "signature", -] - -[[package]] -name = "embassy-boot-nrf" -version = "0.3.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" -dependencies = [ - "cfg-if", - "cortex-m 0.7.7", - "cortex-m-rt", - "embassy-boot", - "embassy-nrf", - "embassy-sync", - "embedded-storage", - "embedded-storage-async", -] - [[package]] name = "embassy-embedded-hal" version = "0.2.0" @@ -1387,12 +1330,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" - [[package]] name = "siphasher" version = "0.3.11" @@ -1643,8 +1580,6 @@ dependencies = [ "defmt-rtt", "display-interface", "display-interface-spi", - "embassy-boot", - "embassy-boot-nrf", "embassy-embedded-hal", "embassy-executor", "embassy-futures", diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 5ff18d8..cb88a33 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -14,8 +14,6 @@ embassy-sync = { version = "0.6" } embassy-executor = { version = "0.6", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-nrf = { version = "0.2", features = ["defmt", "nrf52832", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } -embassy-boot-nrf = { version = "0.3" } -embassy-boot = { version = "0.3" } embedded-io = "0.6" embedded-io-async = "0.6" embedded-storage = "0.3" @@ -65,8 +63,6 @@ embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79a embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } -embassy-boot = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } -embassy-boot-nrf = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } [profile.release] debug = 2 diff --git a/firmware/memory.x b/firmware/memory.x index fa26fb1..c62110a 100644 --- a/firmware/memory.x +++ b/firmware/memory.x @@ -1,19 +1,6 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - MBR : ORIGIN = 0x00000000, LENGTH = 4K - SOFTDEVICE : ORIGIN = 0x00001000, LENGTH = 148K - FLASH : ORIGIN = 0x00026000, LENGTH = 324K - BOOTLOADER : ORIGIN = 0x00077000, LENGTH = 32K - BOOTLOADER_STATE : ORIGIN = 0x0007F000, LENGTH = 4K - - DFU : ORIGIN = 0x00000000, LENGTH = 328K - + FLASH : ORIGIN = 0x00008020, LENGTH = 256K RAM : ORIGIN = 0x20000008, LENGTH = 32760 } - -__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); -__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); - -__bootloader_dfu_start = ORIGIN(DFU); -__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); diff --git a/firmware/src/ble.rs b/firmware/src/ble.rs index 4a7e564..d427be1 100644 --- a/firmware/src/ble.rs +++ b/firmware/src/ble.rs @@ -270,17 +270,18 @@ async fn process( if let Some(DfuStatus::DoneReset) = server.handle(&mut target, &mut dfu, connection, value_handle).await { - let mut magic = crate::AlignedBuffer([0; 4]); - let mut state = embassy_boot::FirmwareState::new(dfu_config.state(), &mut magic.0); - match state.mark_updated().await { - Ok(_) => { - info!("Firmware updated, resetting"); - cortex_m::peripheral::SCB::sys_reset(); - } - Err(e) => { - panic!("Error marking firmware updated: {:?}", e); - } - } + warn!("Supposed to reset!"); + //let mut magic = crate::AlignedBuffer([0; 4]); + //let mut state = embassy_boot::FirmwareState::new(dfu_config.state(), &mut magic.0); + //match state.mark_updated().await { + // Ok(_) => { + // info!("Firmware updated, resetting"); + // cortex_m::peripheral::SCB::sys_reset(); + // } + // Err(e) => { + // panic!("Error marking firmware updated: {:?}", e); + // } + //} } } _ => {} diff --git a/firmware/src/device.rs b/firmware/src/device.rs index 18ae8ec..e2bc268 100644 --- a/firmware/src/device.rs +++ b/firmware/src/device.rs @@ -1,5 +1,4 @@ use display_interface_spi::SPIInterface; -use embassy_boot_nrf::FirmwareState; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_futures::select::{select, Either}; @@ -26,7 +25,6 @@ pub struct Device<'a> { pub screen: Screen<'static>, pub button: Button, pub battery: Battery<'static>, - pub firmware: FirmwareState<'a, crate::StatePartition<'static>>, pub touchpad: Touchpad<'static>, pub hrs: Hrs<'static>, } diff --git a/firmware/src/main.rs b/firmware/src/main.rs index fc2ca3e..a358457 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -6,7 +6,6 @@ use core::cell::RefCell; use defmt::unwrap; use defmt_rtt as _; use display_interface_spi::SPIInterface; -use embassy_boot_nrf::{AlignedBuffer, FirmwareState}; use embassy_embedded_hal::flash::partition::{BlockingPartition, Partition}; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; @@ -183,8 +182,6 @@ async fn main(s: Spawner) { // DFU setup let dfu_config = DfuConfig::new(internal_flash, external_flash); - let mut magic = AlignedBuffer([0; 4]); - let fw: FirmwareState<'_, _> = FirmwareState::new(dfu_config.state(), &mut magic.0); // BLE ble::start(s, sdc, dfu_config); @@ -210,7 +207,6 @@ async fn main(s: Spawner) { screen, button: btn, battery, - firmware: fw, touchpad, hrs, }; @@ -252,21 +248,14 @@ impl<'a> DfuConfig<'a> { internal: &'a Mutex, external: &'a BMutex>, ) -> Self { - extern "C" { - static __bootloader_state_start: u32; - static __bootloader_state_end: u32; - static __bootloader_dfu_start: u32; - static __bootloader_dfu_end: u32; - } - unsafe { - let dfu_start = &__bootloader_dfu_start as *const u32 as u32; - let dfu_end = &__bootloader_dfu_end as *const u32 as u32; + let dfu_start = u32::MAX; + let dfu_end = u32::MAX; BlockingPartition::new(external, dfu_start, dfu_end - dfu_start); - let state_start = &__bootloader_state_start as *const u32 as u32; - let state_end = &__bootloader_state_end as *const u32 as u32; + let state_start = u32::MAX; + let state_end = u32::MAX; Partition::new(internal, state_start, state_end - state_start); Self { diff --git a/firmware/src/state.rs b/firmware/src/state.rs index fde37d9..7d75459 100644 --- a/firmware/src/state.rs +++ b/firmware/src/state.rs @@ -1,5 +1,4 @@ use defmt::info; -use embassy_boot::State as FwState; use embassy_futures::select::{select, select3, Either, Either3}; use embassy_time::{Duration, Instant, Timer}; use embedded_graphics::prelude::*; @@ -216,18 +215,23 @@ impl MenuState { cortex_m::peripheral::SCB::sys_reset(); } MenuAction::FirmwareSettings => { + /* let validated = FwState::Boot == device .firmware .get_state() .await .expect("Failed to read firmware state"); + */ + let validated = false; WatchState::Menu(MenuState::new(MenuView::firmware_settings( firmware_details(&mut device.battery, validated).await, ))) } MenuAction::ValidateFirmware => { info!("Validate firmware"); + WatchState::Time(TimeState::new(device, Timeout::new(IDLE_TIMEOUT)).await) + /* let validated = FwState::Boot == device .firmware @@ -246,7 +250,7 @@ impl MenuState { WatchState::Menu(MenuState::new(MenuView::firmware_settings( firmware_details(&mut device.battery, validated).await, ))) - } + }*/ } }, } diff --git a/tools/mcuboot/README b/tools/mcuboot/README new file mode 100644 index 0000000..feb5d2f --- /dev/null +++ b/tools/mcuboot/README @@ -0,0 +1 @@ +This whole folder comes from MCUBoot source files (commit 9015a5d404c2c688166cab81067be53c860d98f4). \ No newline at end of file diff --git a/tools/mcuboot/assemble.py b/tools/mcuboot/assemble.py new file mode 100644 index 0000000..f2ce4a1 --- /dev/null +++ b/tools/mcuboot/assemble.py @@ -0,0 +1,131 @@ +#! /usr/bin/env python3 +# +# Copyright 2017 Linaro Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Assemble multiple images into a single image that can be flashed on the device. +""" + +import argparse +import errno +import io +import re +import os.path +import sys + +ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") +if not ZEPHYR_BASE: + sys.exit("$ZEPHYR_BASE environment variable undefined") + +sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts", "dts")) +import edtlib + +def same_keys(a, b): + """Determine if the dicts a and b have the same keys in them""" + for ak in a.keys(): + if ak not in b: + return False + for bk in b.keys(): + if bk not in a: + return False + return True + +offset_re = re.compile(r"^#define DT_FLASH_AREA_([0-9A-Z_]+)_OFFSET(_0)?\s+(0x[0-9a-fA-F]+|[0-9]+)$") +size_re = re.compile(r"^#define DT_FLASH_AREA_([0-9A-Z_]+)_SIZE(_0)?\s+(0x[0-9a-fA-F]+|[0-9]+)$") + +class Assembly(): + def __init__(self, output, bootdir, edt): + self.find_slots(edt) + try: + os.unlink(output) + except OSError as e: + if e.errno != errno.ENOENT: + raise + self.output = output + + def find_slots(self, edt): + offsets = {} + sizes = {} + + part_nodes = edt.compat2nodes["fixed-partitions"] + for node in part_nodes: + for child in node.children.values(): + if "label" in child.props: + label = child.props["label"].val + offsets[label] = child.regs[0].addr + sizes[label] = child.regs[0].size + + if not same_keys(offsets, sizes): + raise Exception("Inconsistent data in devicetree.h") + + # We care about the mcuboot, image-0, and image-1 partitions. + if 'mcuboot' not in offsets: + raise Exception("Board partition table does not have mcuboot partition") + + if 'image-0' not in offsets: + raise Exception("Board partition table does not have image-0 partition") + + if 'image-1' not in offsets: + raise Exception("Board partition table does not have image-1 partition") + + self.offsets = offsets + self.sizes = sizes + + def add_image(self, source, partition): + with open(self.output, 'ab') as ofd: + pos = ofd.tell() + print("partition {}, pos={}, offset={}".format(partition, pos, self.offsets[partition])) + if pos > self.offsets[partition]: + raise Exception("Partitions not in order, unsupported") + if pos < self.offsets[partition]: + buf = b'\xFF' * (self.offsets[partition] - pos) + ofd.write(buf) + with open(source, 'rb') as rfd: + ibuf = rfd.read() + if len(ibuf) > self.sizes[partition]: + raise Exception("Image {} is too large for partition".format(source)) + ofd.write(ibuf) + +def main(): + parser = argparse.ArgumentParser() + + parser.add_argument('-b', '--bootdir', required=True, + help='Directory of built bootloader') + parser.add_argument('-p', '--primary', required=True, + help='Signed image file for primary image') + parser.add_argument('-s', '--secondary', + help='Signed image file for secondary image') + parser.add_argument('-o', '--output', required=True, + help='Filename to write full image to') + + args = parser.parse_args() + + # Extract board name from path + board = os.path.split(os.path.split(args.bootdir)[0])[1] + + dts_path = os.path.join(args.bootdir, "zephyr", board + ".dts.pre.tmp") + + edt = edtlib.EDT(dts_path, [os.path.join(ZEPHYR_BASE, "dts", "bindings")], + warn_reg_unit_address_mismatch=False) + + output = Assembly(args.output, args.bootdir, edt) + + output.add_image(os.path.join(args.bootdir, 'zephyr', 'zephyr.bin'), 'mcuboot') + output.add_image(args.primary, "image-0") + if args.secondary is not None: + output.add_image(args.secondary, "image-1") + +if __name__ == '__main__': + main() diff --git a/tools/mcuboot/flash.sh b/tools/mcuboot/flash.sh new file mode 100644 index 0000000..a2c58c7 --- /dev/null +++ b/tools/mcuboot/flash.sh @@ -0,0 +1,18 @@ +#! /bin/bash + +source $(dirname $0)/../target.sh + +lscript=/tmp/flash$$.jlink + +cat >$lscript < $gscript < {}; +let + # Nixpkgs has fairly recent versions of the dependencies, so we can + # rely on them without having to build our own derivations. + imgtoolPythonEnv = python37.withPackages ( + _: [ + python37.pkgs.click + python37.pkgs.cryptography + python37.pkgs.intelhex + python37.pkgs.setuptools + python37.pkgs.cbor + ] + ); +in +myEnvFun { + name = "imgtool"; + + buildInputs = [ imgtoolPythonEnv ]; +} diff --git a/tools/mcuboot/imgtool.py b/tools/mcuboot/imgtool.py new file mode 100755 index 0000000..7861474 --- /dev/null +++ b/tools/mcuboot/imgtool.py @@ -0,0 +1,20 @@ +#! /usr/bin/env python3 +# +# Copyright 2017 Linaro Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from imgtool import main + +if __name__ == '__main__': + main.imgtool() diff --git a/tools/mcuboot/imgtool/__init__.py b/tools/mcuboot/imgtool/__init__.py new file mode 100644 index 0000000..c0c3ef2 --- /dev/null +++ b/tools/mcuboot/imgtool/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2017 Linaro Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +imgtool_version = "1.6.0rc2" diff --git a/tools/mcuboot/imgtool/boot_record.py b/tools/mcuboot/imgtool/boot_record.py new file mode 100644 index 0000000..28797c3 --- /dev/null +++ b/tools/mcuboot/imgtool/boot_record.py @@ -0,0 +1,50 @@ +# Copyright (c) 2019, Arm Limited. +# Copyright (c) 2020, Linaro Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from enum import Enum +try: + import cbor2 as cbor +except: + import cbor + + +class SwComponent(int, Enum): + """ + Software component property IDs specified by + Arm's PSA Attestation API 1.0 document. + """ + TYPE = 1 + MEASUREMENT_VALUE = 2 + VERSION = 4 + SIGNER_ID = 5 + MEASUREMENT_DESCRIPTION = 6 + + +def create_sw_component_data(sw_type, sw_version, sw_measurement_description, + sw_measurement_value, sw_signer_id): + + # List of software component properties (Key ID + value) + properties = { + SwComponent.TYPE: sw_type, + SwComponent.VERSION: sw_version, + SwComponent.SIGNER_ID: sw_signer_id, + SwComponent.MEASUREMENT_DESCRIPTION: sw_measurement_description, + } + + # Note: The measurement value must be the last item of the property + # list because later it will be modified by the bootloader. + properties[SwComponent.MEASUREMENT_VALUE] = sw_measurement_value + + return cbor.dumps(properties) diff --git a/tools/mcuboot/imgtool/image.py b/tools/mcuboot/imgtool/image.py new file mode 100644 index 0000000..291134d --- /dev/null +++ b/tools/mcuboot/imgtool/image.py @@ -0,0 +1,552 @@ +# Copyright 2018 Nordic Semiconductor ASA +# Copyright 2017 Linaro Limited +# Copyright 2019-2020 Arm Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Image signing and management. +""" + +from . import version as versmod +from .boot_record import create_sw_component_data +import click +from enum import Enum +from intelhex import IntelHex +import hashlib +import struct +import os.path +from .keys import rsa, ecdsa, x25519 +from cryptography.hazmat.primitives.asymmetric import ec, padding +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.kdf.hkdf import HKDF +from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, hmac +from cryptography.exceptions import InvalidSignature + +IMAGE_MAGIC = 0x96f3b83d +IMAGE_HEADER_SIZE = 32 +BIN_EXT = "bin" +INTEL_HEX_EXT = "hex" +DEFAULT_MAX_SECTORS = 128 +MAX_ALIGN = 8 +DEP_IMAGES_KEY = "images" +DEP_VERSIONS_KEY = "versions" +MAX_SW_TYPE_LENGTH = 12 # Bytes + +# Image header flags. +IMAGE_F = { + 'PIC': 0x0000001, + 'NON_BOOTABLE': 0x0000010, + 'RAM_LOAD': 0x0000020, + 'ENCRYPTED': 0x0000004, +} + +TLV_VALUES = { + 'KEYHASH': 0x01, + 'PUBKEY': 0x02, + 'SHA256': 0x10, + 'RSA2048': 0x20, + 'ECDSA224': 0x21, + 'ECDSA256': 0x22, + 'RSA3072': 0x23, + 'ED25519': 0x24, + 'ENCRSA2048': 0x30, + 'ENCKW128': 0x31, + 'ENCEC256': 0x32, + 'ENCX25519': 0x33, + 'DEPENDENCY': 0x40, + 'SEC_CNT': 0x50, + 'BOOT_RECORD': 0x60, +} + +TLV_SIZE = 4 +TLV_INFO_SIZE = 4 +TLV_INFO_MAGIC = 0x6907 +TLV_PROT_INFO_MAGIC = 0x6908 + +boot_magic = bytes([ + 0x77, 0xc2, 0x95, 0xf3, + 0x60, 0xd2, 0xef, 0x7f, + 0x35, 0x52, 0x50, 0x0f, + 0x2c, 0xb6, 0x79, 0x80, ]) + +STRUCT_ENDIAN_DICT = { + 'little': '<', + 'big': '>' +} + +VerifyResult = Enum('VerifyResult', + """ + OK INVALID_MAGIC INVALID_TLV_INFO_MAGIC INVALID_HASH + INVALID_SIGNATURE + """) + + +class TLV(): + def __init__(self, endian, magic=TLV_INFO_MAGIC): + self.magic = magic + self.buf = bytearray() + self.endian = endian + + def __len__(self): + return TLV_INFO_SIZE + len(self.buf) + + def add(self, kind, payload): + """ + Add a TLV record. Kind should be a string found in TLV_VALUES above. + """ + e = STRUCT_ENDIAN_DICT[self.endian] + buf = struct.pack(e + 'BBH', TLV_VALUES[kind], 0, len(payload)) + self.buf += buf + self.buf += payload + + def get(self): + if len(self.buf) == 0: + return bytes() + e = STRUCT_ENDIAN_DICT[self.endian] + header = struct.pack(e + 'HH', self.magic, len(self)) + return header + bytes(self.buf) + + +class Image(): + + def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, + pad_header=False, pad=False, confirm=False, align=1, + slot_size=0, max_sectors=DEFAULT_MAX_SECTORS, + overwrite_only=False, endian="little", load_addr=0, + erased_val=None, save_enctlv=False, security_counter=None): + self.version = version or versmod.decode_version("0") + self.header_size = header_size + self.pad_header = pad_header + self.pad = pad + self.confirm = confirm + self.align = align + self.slot_size = slot_size + self.max_sectors = max_sectors + self.overwrite_only = overwrite_only + self.endian = endian + self.base_addr = None + self.load_addr = 0 if load_addr is None else load_addr + self.erased_val = 0xff if erased_val is None else int(erased_val, 0) + self.payload = [] + self.enckey = None + self.save_enctlv = save_enctlv + self.enctlv_len = 0 + + if security_counter == 'auto': + # Security counter has not been explicitly provided, + # generate it from the version number + self.security_counter = ((self.version.major << 24) + + (self.version.minor << 16) + + self.version.revision) + else: + self.security_counter = security_counter + + def __repr__(self): + return "".format( + self.version, + self.header_size, + self.security_counter, + self.base_addr if self.base_addr is not None else "N/A", + self.load_addr, + self.align, + self.slot_size, + self.max_sectors, + self.overwrite_only, + self.endian, + self.__class__.__name__, + len(self.payload)) + + def load(self, path): + """Load an image from a given file""" + ext = os.path.splitext(path)[1][1:].lower() + try: + if ext == INTEL_HEX_EXT: + ih = IntelHex(path) + self.payload = ih.tobinarray() + self.base_addr = ih.minaddr() + else: + with open(path, 'rb') as f: + self.payload = f.read() + except FileNotFoundError: + raise click.UsageError("Input file not found") + + # Add the image header if needed. + if self.pad_header and self.header_size > 0: + if self.base_addr: + # Adjust base_addr for new header + self.base_addr -= self.header_size + self.payload = bytes([self.erased_val] * self.header_size) + \ + self.payload + + self.check_header() + + def save(self, path, hex_addr=None): + """Save an image from a given file""" + ext = os.path.splitext(path)[1][1:].lower() + if ext == INTEL_HEX_EXT: + # input was in binary format, but HEX needs to know the base addr + if self.base_addr is None and hex_addr is None: + raise click.UsageError("No address exists in input file " + "neither was it provided by user") + h = IntelHex() + if hex_addr is not None: + self.base_addr = hex_addr + h.frombytes(bytes=self.payload, offset=self.base_addr) + if self.pad: + trailer_size = self._trailer_size(self.align, self.max_sectors, + self.overwrite_only, + self.enckey, + self.save_enctlv, + self.enctlv_len) + trailer_addr = (self.base_addr + self.slot_size) - trailer_size + padding = bytes([self.erased_val] * + (trailer_size - len(boot_magic))) + boot_magic + h.puts(trailer_addr, padding) + h.tofile(path, 'hex') + else: + if self.pad: + self.pad_to(self.slot_size) + with open(path, 'wb') as f: + f.write(self.payload) + + def check_header(self): + if self.header_size > 0 and not self.pad_header: + if any(v != 0 for v in self.payload[0:self.header_size]): + raise click.UsageError("Header padding was not requested and " + "image does not start with zeros") + + def check_trailer(self): + if self.slot_size > 0: + tsize = self._trailer_size(self.align, self.max_sectors, + self.overwrite_only, self.enckey, + self.save_enctlv, self.enctlv_len) + padding = self.slot_size - (len(self.payload) + tsize) + if padding < 0: + msg = "Image size (0x{:x}) + trailer (0x{:x}) exceeds " \ + "requested size 0x{:x}".format( + len(self.payload), tsize, self.slot_size) + raise click.UsageError(msg) + + def ecies_hkdf(self, enckey, plainkey): + if isinstance(enckey, ecdsa.ECDSA256P1Public): + newpk = ec.generate_private_key(ec.SECP256R1(), default_backend()) + shared = newpk.exchange(ec.ECDH(), enckey._get_public()) + else: + newpk = X25519PrivateKey.generate() + shared = newpk.exchange(enckey._get_public()) + derived_key = HKDF( + algorithm=hashes.SHA256(), length=48, salt=None, + info=b'MCUBoot_ECIES_v1', backend=default_backend()).derive(shared) + encryptor = Cipher(algorithms.AES(derived_key[:16]), + modes.CTR(bytes([0] * 16)), + backend=default_backend()).encryptor() + cipherkey = encryptor.update(plainkey) + encryptor.finalize() + mac = hmac.HMAC(derived_key[16:], hashes.SHA256(), + backend=default_backend()) + mac.update(cipherkey) + ciphermac = mac.finalize() + if isinstance(enckey, ecdsa.ECDSA256P1Public): + pubk = newpk.public_key().public_bytes( + encoding=Encoding.X962, + format=PublicFormat.UncompressedPoint) + else: + pubk = newpk.public_key().public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw) + return cipherkey, ciphermac, pubk + + def create(self, key, public_key_format, enckey, dependencies=None, + sw_type=None): + self.enckey = enckey + + # Calculate the hash of the public key + if key is not None: + pub = key.get_public_bytes() + sha = hashlib.sha256() + sha.update(pub) + pubbytes = sha.digest() + else: + pubbytes = bytes(hashlib.sha256().digest_size) + + protected_tlv_size = 0 + + if self.security_counter is not None: + # Size of the security counter TLV: header ('HH') + payload ('I') + # = 4 + 4 = 8 Bytes + protected_tlv_size += TLV_SIZE + 4 + + if sw_type is not None: + if len(sw_type) > MAX_SW_TYPE_LENGTH: + msg = "'{}' is too long ({} characters) for sw_type. Its " \ + "maximum allowed length is 12 characters.".format( + sw_type, len(sw_type)) + raise click.UsageError(msg) + + image_version = (str(self.version.major) + '.' + + str(self.version.minor) + '.' + + str(self.version.revision)) + + # The image hash is computed over the image header, the image + # itself and the protected TLV area. However, the boot record TLV + # (which is part of the protected area) should contain this hash + # before it is even calculated. For this reason the script fills + # this field with zeros and the bootloader will insert the right + # value later. + digest = bytes(hashlib.sha256().digest_size) + + # Create CBOR encoded boot record + boot_record = create_sw_component_data(sw_type, image_version, + "SHA256", digest, + pubbytes) + + protected_tlv_size += TLV_SIZE + len(boot_record) + + if dependencies is not None: + # Size of a Dependency TLV = Header ('HH') + Payload('IBBHI') + # = 4 + 12 = 16 Bytes + dependencies_num = len(dependencies[DEP_IMAGES_KEY]) + protected_tlv_size += (dependencies_num * 16) + + if protected_tlv_size != 0: + # Add the size of the TLV info header + protected_tlv_size += TLV_INFO_SIZE + + # At this point the image is already on the payload, this adds + # the header to the payload as well + self.add_header(enckey, protected_tlv_size) + + prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC) + + # Protected TLVs must be added first, because they are also included + # in the hash calculation + protected_tlv_off = None + if protected_tlv_size != 0: + + e = STRUCT_ENDIAN_DICT[self.endian] + + if self.security_counter is not None: + payload = struct.pack(e + 'I', self.security_counter) + prot_tlv.add('SEC_CNT', payload) + + if sw_type is not None: + prot_tlv.add('BOOT_RECORD', boot_record) + + if dependencies is not None: + for i in range(dependencies_num): + payload = struct.pack( + e + 'B3x'+'BBHI', + int(dependencies[DEP_IMAGES_KEY][i]), + dependencies[DEP_VERSIONS_KEY][i].major, + dependencies[DEP_VERSIONS_KEY][i].minor, + dependencies[DEP_VERSIONS_KEY][i].revision, + dependencies[DEP_VERSIONS_KEY][i].build + ) + prot_tlv.add('DEPENDENCY', payload) + + protected_tlv_off = len(self.payload) + self.payload += prot_tlv.get() + + tlv = TLV(self.endian) + + # Note that ecdsa wants to do the hashing itself, which means + # we get to hash it twice. + sha = hashlib.sha256() + sha.update(self.payload) + digest = sha.digest() + + tlv.add('SHA256', digest) + + if key is not None: + if public_key_format == 'hash': + tlv.add('KEYHASH', pubbytes) + else: + tlv.add('PUBKEY', pub) + + # `sign` expects the full image payload (sha256 done internally), + # while `sign_digest` expects only the digest of the payload + + if hasattr(key, 'sign'): + sig = key.sign(bytes(self.payload)) + else: + sig = key.sign_digest(digest) + tlv.add(key.sig_tlv(), sig) + + # At this point the image was hashed + signed, we can remove the + # protected TLVs from the payload (will be re-added later) + if protected_tlv_off is not None: + self.payload = self.payload[:protected_tlv_off] + + if enckey is not None: + plainkey = os.urandom(16) + + if isinstance(enckey, rsa.RSAPublic): + cipherkey = enckey._get_public().encrypt( + plainkey, padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None)) + self.enctlv_len = len(cipherkey) + tlv.add('ENCRSA2048', cipherkey) + elif isinstance(enckey, (ecdsa.ECDSA256P1Public, + x25519.X25519Public)): + cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey) + enctlv = pubk + mac + cipherkey + self.enctlv_len = len(enctlv) + if isinstance(enckey, ecdsa.ECDSA256P1Public): + tlv.add('ENCEC256', enctlv) + else: + tlv.add('ENCX25519', enctlv) + + nonce = bytes([0] * 16) + cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce), + backend=default_backend()) + encryptor = cipher.encryptor() + img = bytes(self.payload[self.header_size:]) + self.payload[self.header_size:] = \ + encryptor.update(img) + encryptor.finalize() + + self.payload += prot_tlv.get() + self.payload += tlv.get() + + self.check_trailer() + + def add_header(self, enckey, protected_tlv_size): + """Install the image header.""" + + flags = 0 + if enckey is not None: + flags |= IMAGE_F['ENCRYPTED'] + if self.load_addr != 0: + # Indicates that this image should be loaded into RAM + # instead of run directly from flash. + flags |= IMAGE_F['RAM_LOAD'] + + e = STRUCT_ENDIAN_DICT[self.endian] + fmt = (e + + # type ImageHdr struct { + 'I' + # Magic uint32 + 'I' + # LoadAddr uint32 + 'H' + # HdrSz uint16 + 'H' + # PTLVSz uint16 + 'I' + # ImgSz uint32 + 'I' + # Flags uint32 + 'BBHI' + # Vers ImageVersion + 'I' # Pad1 uint32 + ) # } + assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE + header = struct.pack(fmt, + IMAGE_MAGIC, + self.load_addr, + self.header_size, + protected_tlv_size, # TLV Info header + Protected TLVs + len(self.payload) - self.header_size, # ImageSz + flags, + self.version.major, + self.version.minor or 0, + self.version.revision or 0, + self.version.build or 0, + 0) # Pad1 + self.payload = bytearray(self.payload) + self.payload[:len(header)] = header + + def _trailer_size(self, write_size, max_sectors, overwrite_only, enckey, + save_enctlv, enctlv_len): + # NOTE: should already be checked by the argument parser + magic_size = 16 + if overwrite_only: + return MAX_ALIGN * 2 + magic_size + else: + if write_size not in set([1, 2, 4, 8]): + raise click.BadParameter("Invalid alignment: {}".format( + write_size)) + m = DEFAULT_MAX_SECTORS if max_sectors is None else max_sectors + trailer = m * 3 * write_size # status area + if enckey is not None: + if save_enctlv: + # TLV saved by the bootloader is aligned + keylen = (int((enctlv_len - 1) / MAX_ALIGN) + 1) * MAX_ALIGN + else: + keylen = 16 + trailer += keylen * 2 # encryption keys + trailer += MAX_ALIGN * 4 # image_ok/copy_done/swap_info/swap_size + trailer += magic_size + return trailer + + def pad_to(self, size): + """Pad the image to the given size, with the given flash alignment.""" + tsize = self._trailer_size(self.align, self.max_sectors, + self.overwrite_only, self.enckey, + self.save_enctlv, self.enctlv_len) + padding = size - (len(self.payload) + tsize) + pbytes = bytearray([self.erased_val] * padding) + pbytes += bytearray([self.erased_val] * (tsize - len(boot_magic))) + if self.confirm and not self.overwrite_only: + pbytes[-MAX_ALIGN] = 0x01 # image_ok = 0x01 + pbytes += boot_magic + self.payload += pbytes + + @staticmethod + def verify(imgfile, key): + with open(imgfile, "rb") as f: + b = f.read() + + magic, _, header_size, _, img_size = struct.unpack('IIHHI', b[:16]) + version = struct.unpack('BBHI', b[20:28]) + + if magic != IMAGE_MAGIC: + return VerifyResult.INVALID_MAGIC, None + + tlv_info = b[header_size+img_size:header_size+img_size+TLV_INFO_SIZE] + magic, tlv_tot = struct.unpack('HH', tlv_info) + if magic != TLV_INFO_MAGIC: + return VerifyResult.INVALID_TLV_INFO_MAGIC, None + + sha = hashlib.sha256() + sha.update(b[:header_size+img_size]) + digest = sha.digest() + + tlv_off = header_size + img_size + tlv_end = tlv_off + tlv_tot + tlv_off += TLV_INFO_SIZE # skip tlv info + while tlv_off < tlv_end: + tlv = b[tlv_off:tlv_off+TLV_SIZE] + tlv_type, _, tlv_len = struct.unpack('BBH', tlv) + if tlv_type == TLV_VALUES["SHA256"]: + off = tlv_off + TLV_SIZE + if digest == b[off:off+tlv_len]: + if key is None: + return VerifyResult.OK, version + else: + return VerifyResult.INVALID_HASH, None + elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]: + off = tlv_off + TLV_SIZE + tlv_sig = b[off:off+tlv_len] + payload = b[:header_size+img_size] + try: + if hasattr(key, 'verify'): + key.verify(tlv_sig, payload) + else: + key.verify_digest(tlv_sig, digest) + return VerifyResult.OK, version + except InvalidSignature: + # continue to next TLV + pass + tlv_off += TLV_SIZE + tlv_len + return VerifyResult.INVALID_SIGNATURE, None diff --git a/tools/mcuboot/imgtool/keys/__init__.py b/tools/mcuboot/imgtool/keys/__init__.py new file mode 100644 index 0000000..f25e2aa --- /dev/null +++ b/tools/mcuboot/imgtool/keys/__init__.py @@ -0,0 +1,94 @@ +# Copyright 2017 Linaro Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Cryptographic key management for imgtool. +""" + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKey, RSAPublicKey) +from cryptography.hazmat.primitives.asymmetric.ec import ( + EllipticCurvePrivateKey, EllipticCurvePublicKey) +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, Ed25519PublicKey) +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey, X25519PublicKey) + +from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES +from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError +from .ed25519 import Ed25519, Ed25519Public, Ed25519UsageError +from .x25519 import X25519, X25519Public, X25519UsageError + + +class PasswordRequired(Exception): + """Raised to indicate that the key is password protected, but a + password was not specified.""" + pass + + +def load(path, passwd=None): + """Try loading a key from the given path. Returns None if the password wasn't specified.""" + with open(path, 'rb') as f: + raw_pem = f.read() + try: + pk = serialization.load_pem_private_key( + raw_pem, + password=passwd, + backend=default_backend()) + # Unfortunately, the crypto library raises unhelpful exceptions, + # so we have to look at the text. + except TypeError as e: + msg = str(e) + if "private key is encrypted" in msg: + return None + raise e + except ValueError: + # This seems to happen if the key is a public key, let's try + # loading it as a public key. + pk = serialization.load_pem_public_key( + raw_pem, + backend=default_backend()) + + if isinstance(pk, RSAPrivateKey): + if pk.key_size not in RSA_KEY_SIZES: + raise Exception("Unsupported RSA key size: " + pk.key_size) + return RSA(pk) + elif isinstance(pk, RSAPublicKey): + if pk.key_size not in RSA_KEY_SIZES: + raise Exception("Unsupported RSA key size: " + pk.key_size) + return RSAPublic(pk) + elif isinstance(pk, EllipticCurvePrivateKey): + if pk.curve.name != 'secp256r1': + raise Exception("Unsupported EC curve: " + pk.curve.name) + if pk.key_size != 256: + raise Exception("Unsupported EC size: " + pk.key_size) + return ECDSA256P1(pk) + elif isinstance(pk, EllipticCurvePublicKey): + if pk.curve.name != 'secp256r1': + raise Exception("Unsupported EC curve: " + pk.curve.name) + if pk.key_size != 256: + raise Exception("Unsupported EC size: " + pk.key_size) + return ECDSA256P1Public(pk) + elif isinstance(pk, Ed25519PrivateKey): + return Ed25519(pk) + elif isinstance(pk, Ed25519PublicKey): + return Ed25519Public(pk) + elif isinstance(pk, X25519PrivateKey): + return X25519(pk) + elif isinstance(pk, X25519PublicKey): + return X25519Public(pk) + else: + raise Exception("Unknown key type: " + str(type(pk))) diff --git a/tools/mcuboot/imgtool/keys/ecdsa.py b/tools/mcuboot/imgtool/keys/ecdsa.py new file mode 100644 index 0000000..139d583 --- /dev/null +++ b/tools/mcuboot/imgtool/keys/ecdsa.py @@ -0,0 +1,157 @@ +""" +ECDSA key management +""" + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.hashes import SHA256 + +from .general import KeyClass + +class ECDSAUsageError(Exception): + pass + +class ECDSA256P1Public(KeyClass): + def __init__(self, key): + self.key = key + + def shortname(self): + return "ecdsa" + + def _unsupported(self, name): + raise ECDSAUsageError("Operation {} requires private key".format(name)) + + def _get_public(self): + return self.key + + def get_public_bytes(self): + # The key is embedded into MBUboot in "SubjectPublicKeyInfo" format + return self._get_public().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + + def get_private_bytes(self, minimal): + self._unsupported('get_private_bytes') + + def export_private(self, path, passwd=None): + self._unsupported('export_private') + + def export_public(self, path): + """Write the public key to the given file.""" + pem = self._get_public().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + with open(path, 'wb') as f: + f.write(pem) + + def sig_type(self): + return "ECDSA256_SHA256" + + def sig_tlv(self): + return "ECDSA256" + + def sig_len(self): + # Early versions of MCUboot (< v1.5.0) required ECDSA + # signatures to be padded to 72 bytes. Because the DER + # encoding is done with signed integers, the size of the + # signature will vary depending on whether the high bit is set + # in each value. This padding was done in a + # not-easily-reversible way (by just adding zeros). + # + # The signing code no longer requires this padding, and newer + # versions of MCUboot don't require it. But, continue to + # return the total length so that the padding can be done if + # requested. + return 72 + + def verify(self, signature, payload): + # strip possible paddings added during sign + signature = signature[:signature[1] + 2] + k = self.key + if isinstance(self.key, ec.EllipticCurvePrivateKey): + k = self.key.public_key() + return k.verify(signature=signature, data=payload, + signature_algorithm=ec.ECDSA(SHA256())) + + +class ECDSA256P1(ECDSA256P1Public): + """ + Wrapper around an ECDSA private key. + """ + + def __init__(self, key): + """key should be an instance of EllipticCurvePrivateKey""" + self.key = key + self.pad_sig = False + + @staticmethod + def generate(): + pk = ec.generate_private_key( + ec.SECP256R1(), + backend=default_backend()) + return ECDSA256P1(pk) + + def _get_public(self): + return self.key.public_key() + + def _build_minimal_ecdsa_privkey(self, der): + ''' + Builds a new DER that only includes the EC private key, removing the + public key that is added as an "optional" BITSTRING. + ''' + offset_PUB = 68 + EXCEPTION_TEXT = "Error parsing ecdsa key. Please submit an issue!" + if der[offset_PUB] != 0xa1: + raise ECDSAUsageError(EXCEPTION_TEXT) + len_PUB = der[offset_PUB + 1] + b = bytearray(der[:-offset_PUB]) + offset_SEQ = 29 + if b[offset_SEQ] != 0x30: + raise ECDSAUsageError(EXCEPTION_TEXT) + b[offset_SEQ + 1] -= len_PUB + offset_OCT_STR = 27 + if b[offset_OCT_STR] != 0x04: + raise ECDSAUsageError(EXCEPTION_TEXT) + b[offset_OCT_STR + 1] -= len_PUB + if b[0] != 0x30 or b[1] != 0x81: + raise ECDSAUsageError(EXCEPTION_TEXT) + b[2] -= len_PUB + return b + + def get_private_bytes(self, minimal): + priv = self.key.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption()) + if minimal: + priv = self._build_minimal_ecdsa_privkey(priv) + return priv + + def export_private(self, path, passwd=None): + """Write the private key to the given file, protecting it with the optional password.""" + if passwd is None: + enc = serialization.NoEncryption() + else: + enc = serialization.BestAvailableEncryption(passwd) + pem = self.key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=enc) + with open(path, 'wb') as f: + f.write(pem) + + def raw_sign(self, payload): + """Return the actual signature""" + return self.key.sign( + data=payload, + signature_algorithm=ec.ECDSA(SHA256())) + + def sign(self, payload): + sig = self.raw_sign(payload) + if self.pad_sig: + # To make fixed length, pad with one or two zeros. + sig += b'\000' * (self.sig_len() - len(sig)) + return sig + else: + return sig diff --git a/tools/mcuboot/imgtool/keys/ecdsa_test.py b/tools/mcuboot/imgtool/keys/ecdsa_test.py new file mode 100644 index 0000000..7982cad --- /dev/null +++ b/tools/mcuboot/imgtool/keys/ecdsa_test.py @@ -0,0 +1,99 @@ +""" +Tests for ECDSA keys +""" + +import io +import os.path +import sys +import tempfile +import unittest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.hashes import SHA256 + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) + +from imgtool.keys import load, ECDSA256P1, ECDSAUsageError + +class EcKeyGeneration(unittest.TestCase): + + def setUp(self): + self.test_dir = tempfile.TemporaryDirectory() + + def tname(self, base): + return os.path.join(self.test_dir.name, base) + + def tearDown(self): + self.test_dir.cleanup() + + def test_keygen(self): + name1 = self.tname("keygen.pem") + k = ECDSA256P1.generate() + k.export_private(name1, b'secret') + + self.assertIsNone(load(name1)) + + k2 = load(name1, b'secret') + + pubname = self.tname('keygen-pub.pem') + k2.export_public(pubname) + pk2 = load(pubname) + + # We should be able to export the public key from the loaded + # public key, but not the private key. + pk2.export_public(self.tname('keygen-pub2.pem')) + self.assertRaises(ECDSAUsageError, + pk2.export_private, self.tname('keygen-priv2.pem')) + + def test_emit(self): + """Basic sanity check on the code emitters.""" + k = ECDSA256P1.generate() + + ccode = io.StringIO() + k.emit_c_public(ccode) + self.assertIn("ecdsa_pub_key", ccode.getvalue()) + self.assertIn("ecdsa_pub_key_len", ccode.getvalue()) + + rustcode = io.StringIO() + k.emit_rust_public(rustcode) + self.assertIn("ECDSA_PUB_KEY", rustcode.getvalue()) + + def test_emit_pub(self): + """Basic sanity check on the code emitters.""" + pubname = self.tname("public.pem") + k = ECDSA256P1.generate() + k.export_public(pubname) + + k2 = load(pubname) + + ccode = io.StringIO() + k2.emit_c_public(ccode) + self.assertIn("ecdsa_pub_key", ccode.getvalue()) + self.assertIn("ecdsa_pub_key_len", ccode.getvalue()) + + rustcode = io.StringIO() + k2.emit_rust_public(rustcode) + self.assertIn("ECDSA_PUB_KEY", rustcode.getvalue()) + + def test_sig(self): + k = ECDSA256P1.generate() + buf = b'This is the message' + sig = k.raw_sign(buf) + + # The code doesn't have any verification, so verify this + # manually. + k.key.public_key().verify( + signature=sig, + data=buf, + signature_algorithm=ec.ECDSA(SHA256())) + + # Modify the message to make sure the signature fails. + self.assertRaises(InvalidSignature, + k.key.public_key().verify, + signature=sig, + data=b'This is thE message', + signature_algorithm=ec.ECDSA(SHA256())) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/mcuboot/imgtool/keys/ed25519.py b/tools/mcuboot/imgtool/keys/ed25519.py new file mode 100644 index 0000000..fb000cd --- /dev/null +++ b/tools/mcuboot/imgtool/keys/ed25519.py @@ -0,0 +1,105 @@ +""" +ED25519 key management +""" + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ed25519 + +from .general import KeyClass + + +class Ed25519UsageError(Exception): + pass + + +class Ed25519Public(KeyClass): + def __init__(self, key): + self.key = key + + def shortname(self): + return "ed25519" + + def _unsupported(self, name): + raise Ed25519UsageError("Operation {} requires private key".format(name)) + + def _get_public(self): + return self.key + + def get_public_bytes(self): + # The key is embedded into MBUboot in "SubjectPublicKeyInfo" format + return self._get_public().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + + def get_private_bytes(self, minimal): + self._unsupported('get_private_bytes') + + def export_private(self, path, passwd=None): + self._unsupported('export_private') + + def export_public(self, path): + """Write the public key to the given file.""" + pem = self._get_public().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + with open(path, 'wb') as f: + f.write(pem) + + def sig_type(self): + return "ED25519" + + def sig_tlv(self): + return "ED25519" + + def sig_len(self): + return 64 + + +class Ed25519(Ed25519Public): + """ + Wrapper around an ED25519 private key. + """ + + def __init__(self, key): + """key should be an instance of EllipticCurvePrivateKey""" + self.key = key + + @staticmethod + def generate(): + pk = ed25519.Ed25519PrivateKey.generate() + return Ed25519(pk) + + def _get_public(self): + return self.key.public_key() + + def get_private_bytes(self, minimal): + raise Ed25519UsageError("Operation not supported with {} keys".format( + self.shortname())) + + def export_private(self, path, passwd=None): + """ + Write the private key to the given file, protecting it with the + optional password. + """ + if passwd is None: + enc = serialization.NoEncryption() + else: + enc = serialization.BestAvailableEncryption(passwd) + pem = self.key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=enc) + with open(path, 'wb') as f: + f.write(pem) + + def sign_digest(self, digest): + """Return the actual signature""" + return self.key.sign(data=digest) + + def verify_digest(self, signature, digest): + """Verify that signature is valid for given digest""" + k = self.key + if isinstance(self.key, ed25519.Ed25519PrivateKey): + k = self.key.public_key() + return k.verify(signature=signature, data=digest) diff --git a/tools/mcuboot/imgtool/keys/ed25519_test.py b/tools/mcuboot/imgtool/keys/ed25519_test.py new file mode 100644 index 0000000..31f43fe --- /dev/null +++ b/tools/mcuboot/imgtool/keys/ed25519_test.py @@ -0,0 +1,103 @@ +""" +Tests for ECDSA keys +""" + +import hashlib +import io +import os.path +import sys +import tempfile +import unittest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives.asymmetric import ed25519 + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) + +from imgtool.keys import load, Ed25519, Ed25519UsageError + + +class Ed25519KeyGeneration(unittest.TestCase): + + def setUp(self): + self.test_dir = tempfile.TemporaryDirectory() + + def tname(self, base): + return os.path.join(self.test_dir.name, base) + + def tearDown(self): + self.test_dir.cleanup() + + def test_keygen(self): + name1 = self.tname("keygen.pem") + k = Ed25519.generate() + k.export_private(name1, b'secret') + + self.assertIsNone(load(name1)) + + k2 = load(name1, b'secret') + + pubname = self.tname('keygen-pub.pem') + k2.export_public(pubname) + pk2 = load(pubname) + + # We should be able to export the public key from the loaded + # public key, but not the private key. + pk2.export_public(self.tname('keygen-pub2.pem')) + self.assertRaises(Ed25519UsageError, + pk2.export_private, self.tname('keygen-priv2.pem')) + + def test_emit(self): + """Basic sanity check on the code emitters.""" + k = Ed25519.generate() + + ccode = io.StringIO() + k.emit_c_public(ccode) + self.assertIn("ed25519_pub_key", ccode.getvalue()) + self.assertIn("ed25519_pub_key_len", ccode.getvalue()) + + rustcode = io.StringIO() + k.emit_rust_public(rustcode) + self.assertIn("ED25519_PUB_KEY", rustcode.getvalue()) + + def test_emit_pub(self): + """Basic sanity check on the code emitters.""" + pubname = self.tname("public.pem") + k = Ed25519.generate() + k.export_public(pubname) + + k2 = load(pubname) + + ccode = io.StringIO() + k2.emit_c_public(ccode) + self.assertIn("ed25519_pub_key", ccode.getvalue()) + self.assertIn("ed25519_pub_key_len", ccode.getvalue()) + + rustcode = io.StringIO() + k2.emit_rust_public(rustcode) + self.assertIn("ED25519_PUB_KEY", rustcode.getvalue()) + + def test_sig(self): + k = Ed25519.generate() + buf = b'This is the message' + sha = hashlib.sha256() + sha.update(buf) + digest = sha.digest() + sig = k.sign_digest(digest) + + # The code doesn't have any verification, so verify this + # manually. + k.key.public_key().verify(signature=sig, data=digest) + + # Modify the message to make sure the signature fails. + sha = hashlib.sha256() + sha.update(b'This is thE message') + new_digest = sha.digest() + self.assertRaises(InvalidSignature, + k.key.public_key().verify, + signature=sig, + data=new_digest) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/mcuboot/imgtool/keys/general.py b/tools/mcuboot/imgtool/keys/general.py new file mode 100644 index 0000000..ce7a2d2 --- /dev/null +++ b/tools/mcuboot/imgtool/keys/general.py @@ -0,0 +1,45 @@ +"""General key class.""" + +import sys + +AUTOGEN_MESSAGE = "/* Autogenerated by imgtool.py, do not edit. */" + +class KeyClass(object): + def _emit(self, header, trailer, encoded_bytes, indent, file=sys.stdout, len_format=None): + print(AUTOGEN_MESSAGE, file=file) + print(header, end='', file=file) + for count, b in enumerate(encoded_bytes): + if count % 8 == 0: + print("\n" + indent, end='', file=file) + else: + print(" ", end='', file=file) + print("0x{:02x},".format(b), end='', file=file) + print("\n" + trailer, file=file) + if len_format is not None: + print(len_format.format(len(encoded_bytes)), file=file) + + def emit_c_public(self, file=sys.stdout): + self._emit( + header="const unsigned char {}_pub_key[] = {{".format(self.shortname()), + trailer="};", + encoded_bytes=self.get_public_bytes(), + indent=" ", + len_format="const unsigned int {}_pub_key_len = {{}};".format(self.shortname()), + file=file) + + def emit_rust_public(self, file=sys.stdout): + self._emit( + header="static {}_PUB_KEY: &'static [u8] = &[".format(self.shortname().upper()), + trailer="];", + encoded_bytes=self.get_public_bytes(), + indent=" ", + file=file) + + def emit_private(self, minimal, file=sys.stdout): + self._emit( + header="const unsigned char enc_priv_key[] = {", + trailer="};", + encoded_bytes=self.get_private_bytes(minimal), + indent=" ", + len_format="const unsigned int enc_priv_key_len = {};", + file=file) diff --git a/tools/mcuboot/imgtool/keys/rsa.py b/tools/mcuboot/imgtool/keys/rsa.py new file mode 100644 index 0000000..f8273bf --- /dev/null +++ b/tools/mcuboot/imgtool/keys/rsa.py @@ -0,0 +1,163 @@ +""" +RSA Key management +""" + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1 +from cryptography.hazmat.primitives.hashes import SHA256 + +from .general import KeyClass + + +# Sizes that bootutil will recognize +RSA_KEY_SIZES = [2048, 3072] + + +class RSAUsageError(Exception): + pass + + +class RSAPublic(KeyClass): + """The public key can only do a few operations""" + def __init__(self, key): + self.key = key + + def key_size(self): + return self.key.key_size + + def shortname(self): + return "rsa" + + def _unsupported(self, name): + raise RSAUsageError("Operation {} requires private key".format(name)) + + def _get_public(self): + return self.key + + def get_public_bytes(self): + # The key embedded into MCUboot is in PKCS1 format. + return self._get_public().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.PKCS1) + + def get_private_bytes(self, minimal): + self._unsupported('get_private_bytes') + + def export_private(self, path, passwd=None): + self._unsupported('export_private') + + def export_public(self, path): + """Write the public key to the given file.""" + pem = self._get_public().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + with open(path, 'wb') as f: + f.write(pem) + + def sig_type(self): + return "PKCS1_PSS_RSA{}_SHA256".format(self.key_size()) + + def sig_tlv(self): + return"RSA{}".format(self.key_size()) + + def sig_len(self): + return self.key_size() / 8 + + def verify(self, signature, payload): + k = self.key + if isinstance(self.key, rsa.RSAPrivateKey): + k = self.key.public_key() + return k.verify(signature=signature, data=payload, + padding=PSS(mgf=MGF1(SHA256()), salt_length=32), + algorithm=SHA256()) + + +class RSA(RSAPublic): + """ + Wrapper around an RSA key, with imgtool support. + """ + + def __init__(self, key): + """The key should be a private key from cryptography""" + self.key = key + + @staticmethod + def generate(key_size=2048): + if key_size not in RSA_KEY_SIZES: + raise RSAUsageError("Key size {} is not supported by MCUboot" + .format(key_size)) + pk = rsa.generate_private_key( + public_exponent=65537, + key_size=key_size, + backend=default_backend()) + return RSA(pk) + + def _get_public(self): + return self.key.public_key() + + def _build_minimal_rsa_privkey(self, der): + ''' + Builds a new DER that only includes N/E/D/P/Q RSA parameters; + standard DER private bytes provided by OpenSSL also includes + CRT params (DP/DQ/QP) which can be removed. + ''' + OFFSET_N = 7 # N is always located at this offset + b = bytearray(der) + off = OFFSET_N + if b[off + 1] != 0x82: + raise RSAUsageError("Error parsing N while minimizing") + len_N = (b[off + 2] << 8) + b[off + 3] + 4 + off += len_N + if b[off + 1] != 0x03: + raise RSAUsageError("Error parsing E while minimizing") + len_E = b[off + 2] + 4 + off += len_E + if b[off + 1] != 0x82: + raise RSAUsageError("Error parsing D while minimizing") + len_D = (b[off + 2] << 8) + b[off + 3] + 4 + off += len_D + if b[off + 1] != 0x81: + raise RSAUsageError("Error parsing P while minimizing") + len_P = b[off + 2] + 3 + off += len_P + if b[off + 1] != 0x81: + raise RSAUsageError("Error parsing Q while minimizing") + len_Q = b[off + 2] + 3 + off += len_Q + # adjust DER size for removed elements + b[2] = (off - 4) >> 8 + b[3] = (off - 4) & 0xff + return b[:off] + + def get_private_bytes(self, minimal): + priv = self.key.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption()) + if minimal: + priv = self._build_minimal_rsa_privkey(priv) + return priv + + def export_private(self, path, passwd=None): + """Write the private key to the given file, protecting it with the + optional password.""" + if passwd is None: + enc = serialization.NoEncryption() + else: + enc = serialization.BestAvailableEncryption(passwd) + pem = self.key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=enc) + with open(path, 'wb') as f: + f.write(pem) + + def sign(self, payload): + # The verification code only allows the salt length to be the + # same as the hash length, 32. + return self.key.sign( + data=payload, + padding=PSS(mgf=MGF1(SHA256()), salt_length=32), + algorithm=SHA256()) diff --git a/tools/mcuboot/imgtool/keys/rsa_test.py b/tools/mcuboot/imgtool/keys/rsa_test.py new file mode 100644 index 0000000..b0afa83 --- /dev/null +++ b/tools/mcuboot/imgtool/keys/rsa_test.py @@ -0,0 +1,115 @@ +""" +Tests for RSA keys +""" + +import io +import os +import sys +import tempfile +import unittest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1 +from cryptography.hazmat.primitives.hashes import SHA256 + +# Setup sys path so 'imgtool' is in it. +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), + '../..'))) + +from imgtool.keys import load, RSA, RSAUsageError +from imgtool.keys.rsa import RSA_KEY_SIZES + + +class KeyGeneration(unittest.TestCase): + + def setUp(self): + self.test_dir = tempfile.TemporaryDirectory() + + def tname(self, base): + return os.path.join(self.test_dir.name, base) + + def tearDown(self): + self.test_dir.cleanup() + + def test_keygen(self): + # Try generating a RSA key with non-supported size + with self.assertRaises(RSAUsageError): + RSA.generate(key_size=1024) + + for key_size in RSA_KEY_SIZES: + name1 = self.tname("keygen.pem") + k = RSA.generate(key_size=key_size) + k.export_private(name1, b'secret') + + # Try loading the key without a password. + self.assertIsNone(load(name1)) + + k2 = load(name1, b'secret') + + pubname = self.tname('keygen-pub.pem') + k2.export_public(pubname) + pk2 = load(pubname) + + # We should be able to export the public key from the loaded + # public key, but not the private key. + pk2.export_public(self.tname('keygen-pub2.pem')) + self.assertRaises(RSAUsageError, pk2.export_private, + self.tname('keygen-priv2.pem')) + + def test_emit(self): + """Basic sanity check on the code emitters.""" + for key_size in RSA_KEY_SIZES: + k = RSA.generate(key_size=key_size) + + ccode = io.StringIO() + k.emit_c_public(ccode) + self.assertIn("rsa_pub_key", ccode.getvalue()) + self.assertIn("rsa_pub_key_len", ccode.getvalue()) + + rustcode = io.StringIO() + k.emit_rust_public(rustcode) + self.assertIn("RSA_PUB_KEY", rustcode.getvalue()) + + def test_emit_pub(self): + """Basic sanity check on the code emitters, from public key.""" + pubname = self.tname("public.pem") + for key_size in RSA_KEY_SIZES: + k = RSA.generate(key_size=key_size) + k.export_public(pubname) + + k2 = load(pubname) + + ccode = io.StringIO() + k2.emit_c_public(ccode) + self.assertIn("rsa_pub_key", ccode.getvalue()) + self.assertIn("rsa_pub_key_len", ccode.getvalue()) + + rustcode = io.StringIO() + k2.emit_rust_public(rustcode) + self.assertIn("RSA_PUB_KEY", rustcode.getvalue()) + + def test_sig(self): + for key_size in RSA_KEY_SIZES: + k = RSA.generate(key_size=key_size) + buf = b'This is the message' + sig = k.sign(buf) + + # The code doesn't have any verification, so verify this + # manually. + k.key.public_key().verify( + signature=sig, + data=buf, + padding=PSS(mgf=MGF1(SHA256()), salt_length=32), + algorithm=SHA256()) + + # Modify the message to make sure the signature fails. + self.assertRaises(InvalidSignature, + k.key.public_key().verify, + signature=sig, + data=b'This is thE message', + padding=PSS(mgf=MGF1(SHA256()), salt_length=32), + algorithm=SHA256()) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/mcuboot/imgtool/keys/x25519.py b/tools/mcuboot/imgtool/keys/x25519.py new file mode 100644 index 0000000..63c0b5a --- /dev/null +++ b/tools/mcuboot/imgtool/keys/x25519.py @@ -0,0 +1,107 @@ +""" +X25519 key management +""" + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import x25519 + +from .general import KeyClass + + +class X25519UsageError(Exception): + pass + + +class X25519Public(KeyClass): + def __init__(self, key): + self.key = key + + def shortname(self): + return "x25519" + + def _unsupported(self, name): + raise X25519UsageError("Operation {} requires private key".format(name)) + + def _get_public(self): + return self.key + + def get_public_bytes(self): + # The key is embedded into MBUboot in "SubjectPublicKeyInfo" format + return self._get_public().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + + def get_private_bytes(self, minimal): + self._unsupported('get_private_bytes') + + def export_private(self, path, passwd=None): + self._unsupported('export_private') + + def export_public(self, path): + """Write the public key to the given file.""" + pem = self._get_public().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + with open(path, 'wb') as f: + f.write(pem) + + def sig_type(self): + return "X25519" + + def sig_tlv(self): + return "X25519" + + def sig_len(self): + return 32 + + +class X25519(X25519Public): + """ + Wrapper around an X25519 private key. + """ + + def __init__(self, key): + """key should be an instance of EllipticCurvePrivateKey""" + self.key = key + + @staticmethod + def generate(): + pk = x25519.X25519PrivateKey.generate() + return X25519(pk) + + def _get_public(self): + return self.key.public_key() + + def get_private_bytes(self, minimal): + return self.key.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption()) + + def export_private(self, path, passwd=None): + """ + Write the private key to the given file, protecting it with the + optional password. + """ + if passwd is None: + enc = serialization.NoEncryption() + else: + enc = serialization.BestAvailableEncryption(passwd) + pem = self.key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=enc) + with open(path, 'wb') as f: + f.write(pem) + + def sign_digest(self, digest): + """Return the actual signature""" + return self.key.sign(data=digest) + + def verify_digest(self, signature, digest): + """Verify that signature is valid for given digest""" + k = self.key + if isinstance(self.key, x25519.X25519PrivateKey): + k = self.key.public_key() + return k.verify(signature=signature, data=digest) diff --git a/tools/mcuboot/imgtool/main.py b/tools/mcuboot/imgtool/main.py new file mode 100644 index 0000000..c93addc --- /dev/null +++ b/tools/mcuboot/imgtool/main.py @@ -0,0 +1,352 @@ +#! /usr/bin/env python3 +# +# Copyright 2017-2020 Linaro Limited +# Copyright 2019-2020 Arm Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +import click +import getpass +import imgtool.keys as keys +import sys +from imgtool import image, imgtool_version +from imgtool.version import decode_version +from .keys import ( + RSAUsageError, ECDSAUsageError, Ed25519UsageError, X25519UsageError) + +MIN_PYTHON_VERSION = (3, 6) +if sys.version_info < MIN_PYTHON_VERSION: + sys.exit("Python %s.%s or newer is required by imgtool." + % MIN_PYTHON_VERSION) + + +def gen_rsa2048(keyfile, passwd): + keys.RSA.generate().export_private(path=keyfile, passwd=passwd) + + +def gen_rsa3072(keyfile, passwd): + keys.RSA.generate(key_size=3072).export_private(path=keyfile, + passwd=passwd) + + +def gen_ecdsa_p256(keyfile, passwd): + keys.ECDSA256P1.generate().export_private(keyfile, passwd=passwd) + + +def gen_ecdsa_p224(keyfile, passwd): + print("TODO: p-224 not yet implemented") + + +def gen_ed25519(keyfile, passwd): + keys.Ed25519.generate().export_private(path=keyfile, passwd=passwd) + + +def gen_x25519(keyfile, passwd): + keys.X25519.generate().export_private(path=keyfile, passwd=passwd) + + +valid_langs = ['c', 'rust'] +keygens = { + 'rsa-2048': gen_rsa2048, + 'rsa-3072': gen_rsa3072, + 'ecdsa-p256': gen_ecdsa_p256, + 'ecdsa-p224': gen_ecdsa_p224, + 'ed25519': gen_ed25519, + 'x25519': gen_x25519, +} + + +def load_key(keyfile): + # TODO: better handling of invalid pass-phrase + key = keys.load(keyfile) + if key is not None: + return key + passwd = getpass.getpass("Enter key passphrase: ").encode('utf-8') + return keys.load(keyfile, passwd) + + +def get_password(): + while True: + passwd = getpass.getpass("Enter key passphrase: ") + passwd2 = getpass.getpass("Reenter passphrase: ") + if passwd == passwd2: + break + print("Passwords do not match, try again") + + # Password must be bytes, always use UTF-8 for consistent + # encoding. + return passwd.encode('utf-8') + + +@click.option('-p', '--password', is_flag=True, + help='Prompt for password to protect key') +@click.option('-t', '--type', metavar='type', required=True, + type=click.Choice(keygens.keys()), prompt=True, + help='{}'.format('One of: {}'.format(', '.join(keygens.keys())))) +@click.option('-k', '--key', metavar='filename', required=True) +@click.command(help='Generate pub/private keypair') +def keygen(type, key, password): + password = get_password() if password else None + keygens[type](key, password) + + +@click.option('-l', '--lang', metavar='lang', default=valid_langs[0], + type=click.Choice(valid_langs)) +@click.option('-k', '--key', metavar='filename', required=True) +@click.command(help='Dump public key from keypair') +def getpub(key, lang): + key = load_key(key) + if key is None: + print("Invalid passphrase") + elif lang == 'c': + key.emit_c_public() + elif lang == 'rust': + key.emit_rust_public() + else: + raise ValueError("BUG: should never get here!") + + +@click.option('--minimal', default=False, is_flag=True, + help='Reduce the size of the dumped private key to include only ' + 'the minimum amount of data required to decrypt. This ' + 'might require changes to the build config. Check the docs!' + ) +@click.option('-k', '--key', metavar='filename', required=True) +@click.command(help='Dump private key from keypair') +def getpriv(key, minimal): + key = load_key(key) + if key is None: + print("Invalid passphrase") + try: + key.emit_private(minimal) + except (RSAUsageError, ECDSAUsageError, Ed25519UsageError, + X25519UsageError) as e: + raise click.UsageError(e) + + +@click.argument('imgfile') +@click.option('-k', '--key', metavar='filename') +@click.command(help="Check that signed image can be verified by given key") +def verify(key, imgfile): + key = load_key(key) if key else None + ret, version = image.Image.verify(imgfile, key) + if ret == image.VerifyResult.OK: + print("Image was correctly validated") + print("Image version: {}.{}.{}+{}".format(*version)) + return + elif ret == image.VerifyResult.INVALID_MAGIC: + print("Invalid image magic; is this an MCUboot image?") + elif ret == image.VerifyResult.INVALID_TLV_INFO_MAGIC: + print("Invalid TLV info magic; is this an MCUboot image?") + elif ret == image.VerifyResult.INVALID_HASH: + print("Image has an invalid sha256 digest") + elif ret == image.VerifyResult.INVALID_SIGNATURE: + print("No signature found for the given key") + else: + print("Unknown return code: {}".format(ret)) + sys.exit(1) + + +def validate_version(ctx, param, value): + try: + decode_version(value) + return value + except ValueError as e: + raise click.BadParameter("{}".format(e)) + + +def validate_security_counter(ctx, param, value): + if value is not None: + if value.lower() == 'auto': + return 'auto' + else: + try: + return int(value, 0) + except ValueError: + raise click.BadParameter( + "{} is not a valid integer. Please use code literals " + "prefixed with 0b/0B, 0o/0O, or 0x/0X as necessary." + .format(value)) + + +def validate_header_size(ctx, param, value): + min_hdr_size = image.IMAGE_HEADER_SIZE + if value < min_hdr_size: + raise click.BadParameter( + "Minimum value for -H/--header-size is {}".format(min_hdr_size)) + return value + + +def get_dependencies(ctx, param, value): + if value is not None: + versions = [] + images = re.findall(r"\((\d+)", value) + if len(images) == 0: + raise click.BadParameter( + "Image dependency format is invalid: {}".format(value)) + raw_versions = re.findall(r",\s*([0-9.+]+)\)", value) + if len(images) != len(raw_versions): + raise click.BadParameter( + '''There's a mismatch between the number of dependency images + and versions in: {}'''.format(value)) + for raw_version in raw_versions: + try: + versions.append(decode_version(raw_version)) + except ValueError as e: + raise click.BadParameter("{}".format(e)) + dependencies = dict() + dependencies[image.DEP_IMAGES_KEY] = images + dependencies[image.DEP_VERSIONS_KEY] = versions + return dependencies + + +class BasedIntParamType(click.ParamType): + name = 'integer' + + def convert(self, value, param, ctx): + try: + return int(value, 0) + except ValueError: + self.fail('%s is not a valid integer. Please use code literals ' + 'prefixed with 0b/0B, 0o/0O, or 0x/0X as necessary.' + % value, param, ctx) + + +@click.argument('outfile') +@click.argument('infile') +@click.option('-R', '--erased-val', type=click.Choice(['0', '0xff']), + required=False, + help='The value that is read back from erased flash.') +@click.option('-x', '--hex-addr', type=BasedIntParamType(), required=False, + help='Adjust address in hex output file.') +@click.option('-L', '--load-addr', type=BasedIntParamType(), required=False, + help='Load address for image when it should run from RAM.') +@click.option('--save-enctlv', default=False, is_flag=True, + help='When upgrading, save encrypted key TLVs instead of plain ' + 'keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option ' + 'was set.') +@click.option('-E', '--encrypt', metavar='filename', + help='Encrypt image using the provided public key') +@click.option('-e', '--endian', type=click.Choice(['little', 'big']), + default='little', help="Select little or big endian") +@click.option('--overwrite-only', default=False, is_flag=True, + help='Use overwrite-only instead of swap upgrades') +@click.option('--boot-record', metavar='sw_type', help='Create CBOR encoded ' + 'boot record TLV. The sw_type represents the role of the ' + 'software component (e.g. CoFM for coprocessor firmware). ' + '[max. 12 characters]') +@click.option('-M', '--max-sectors', type=int, + help='When padding allow for this amount of sectors (defaults ' + 'to 128)') +@click.option('--confirm', default=False, is_flag=True, + help='When padding the image, mark it as confirmed') +@click.option('--pad', default=False, is_flag=True, + help='Pad image to --slot-size bytes, adding trailer magic') +@click.option('-S', '--slot-size', type=BasedIntParamType(), required=True, + help='Size of the slot where the image will be written') +@click.option('--pad-header', default=False, is_flag=True, + help='Add --header-size zeroed bytes at the beginning of the ' + 'image') +@click.option('-H', '--header-size', callback=validate_header_size, + type=BasedIntParamType(), required=True) +@click.option('--pad-sig', default=False, is_flag=True, + help='Add 0-2 bytes of padding to ECDSA signature ' + '(for mcuboot <1.5)') +@click.option('-d', '--dependencies', callback=get_dependencies, + required=False, help='''Add dependence on another image, format: + "(,), ... "''') +@click.option('-s', '--security-counter', callback=validate_security_counter, + help='Specify the value of security counter. Use the `auto` ' + 'keyword to automatically generate it from the image version.') +@click.option('-v', '--version', callback=validate_version, required=True) +@click.option('--align', type=click.Choice(['1', '2', '4', '8']), + required=True) +@click.option('--public-key-format', type=click.Choice(['hash', 'full']), + default='hash', help='In what format to add the public key to ' + 'the image manifest: full key or hash of the key.') +@click.option('-k', '--key', metavar='filename') +@click.command(help='''Create a signed or unsigned image\n + INFILE and OUTFILE are parsed as Intel HEX if the params have + .hex extension, otherwise binary format is used''') +def sign(key, public_key_format, align, version, pad_sig, header_size, + pad_header, slot_size, pad, confirm, max_sectors, overwrite_only, + endian, encrypt, infile, outfile, dependencies, load_addr, hex_addr, + erased_val, save_enctlv, security_counter, boot_record): + img = image.Image(version=decode_version(version), header_size=header_size, + pad_header=pad_header, pad=pad, confirm=confirm, + align=int(align), slot_size=slot_size, + max_sectors=max_sectors, overwrite_only=overwrite_only, + endian=endian, load_addr=load_addr, erased_val=erased_val, + save_enctlv=save_enctlv, + security_counter=security_counter) + img.load(infile) + key = load_key(key) if key else None + enckey = load_key(encrypt) if encrypt else None + if enckey and key: + if ((isinstance(key, keys.ECDSA256P1) and + not isinstance(enckey, keys.ECDSA256P1Public)) + or (isinstance(key, keys.RSA) and + not isinstance(enckey, keys.RSAPublic))): + # FIXME + raise click.UsageError("Signing and encryption must use the same " + "type of key") + + if pad_sig and hasattr(key, 'pad_sig'): + key.pad_sig = True + + img.create(key, public_key_format, enckey, dependencies, boot_record) + img.save(outfile, hex_addr) + + +class AliasesGroup(click.Group): + + _aliases = { + "create": "sign", + } + + def list_commands(self, ctx): + cmds = [k for k in self.commands] + aliases = [k for k in self._aliases] + return sorted(cmds + aliases) + + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + if cmd_name in self._aliases: + return click.Group.get_command(self, ctx, self._aliases[cmd_name]) + return None + + +@click.command(help='Print imgtool version information') +def version(): + print(imgtool_version) + + +@click.command(cls=AliasesGroup, + context_settings=dict(help_option_names=['-h', '--help'])) +def imgtool(): + pass + + +imgtool.add_command(keygen) +imgtool.add_command(getpub) +imgtool.add_command(getpriv) +imgtool.add_command(verify) +imgtool.add_command(sign) +imgtool.add_command(version) + + +if __name__ == '__main__': + imgtool() diff --git a/tools/mcuboot/imgtool/version.py b/tools/mcuboot/imgtool/version.py new file mode 100644 index 0000000..030b012 --- /dev/null +++ b/tools/mcuboot/imgtool/version.py @@ -0,0 +1,53 @@ +# Copyright 2017 Linaro Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Semi Semantic Versioning + +Implements a subset of semantic versioning that is supportable by the image +header. +""" + +from collections import namedtuple +import re + +SemiSemVersion = namedtuple('SemiSemVersion', ['major', 'minor', 'revision', + 'build']) + +version_re = re.compile( + r"""^([1-9]\d*|0)(\.([1-9]\d*|0)(\.([1-9]\d*|0)(\+([1-9]\d*|0))?)?)?$""") + + +def decode_version(text): + """Decode the version string, which should be of the form maj.min.rev+build + """ + m = version_re.match(text) + if m: + result = SemiSemVersion( + int(m.group(1)) if m.group(1) else 0, + int(m.group(3)) if m.group(3) else 0, + int(m.group(5)) if m.group(5) else 0, + int(m.group(7)) if m.group(7) else 0) + return result + else: + msg = "Invalid version number, should be maj.min.rev+build with later " + msg += "parts optional" + raise ValueError(msg) + + +if __name__ == '__main__': + print(decode_version("1.2")) + print(decode_version("1.0")) + print(decode_version("0.0.2+75")) + print(decode_version("0.0.0+00")) diff --git a/tools/mcuboot/jgdb.sh b/tools/mcuboot/jgdb.sh new file mode 100644 index 0000000..a79c87c --- /dev/null +++ b/tools/mcuboot/jgdb.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +source $(dirname $0)/../target.sh + +# Start the jlink gdb server +JLinkGDBServer -if swd -device $SOC -speed auto diff --git a/tools/mcuboot/jl.sh b/tools/mcuboot/jl.sh new file mode 100644 index 0000000..260206d --- /dev/null +++ b/tools/mcuboot/jl.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +source $(dirname $0)/../target.sh + +JLinkExe -speed auto -si SWD -device $SOC diff --git a/tools/mcuboot/mcubin.bt b/tools/mcuboot/mcubin.bt new file mode 100644 index 0000000..e2ec361 --- /dev/null +++ b/tools/mcuboot/mcubin.bt @@ -0,0 +1,135 @@ +// Copyright (C) 2019, Linaro Ltd +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file is a Binary Template file for the 010 Editor +// (http://www.sweetscape.com/010editor/) to allow it to show the +// structure of an MCUboot image. + +LittleEndian(); + +struct ENTRY { + uint32 id; + uint32 offset; + uint32 size; + uint32 pad; +}; + +// The simulator writes the partition table at the beginning of the +// image, so that we can tell where the partitions are. If you are +// trying to view an image captured from a device, you can either +// construct a synthetic partition table in the file, or change code +// described below to hardcode one. +struct PTABLE { + uchar pheader[8]; + if (ptable.pheader != "mcuboot\0") { + // NOTE: Put code here to hard code a partition table, and + // continue. + Warning("Invalid magic on ptable header"); + return -1; + } else { + uint32 count; + struct ENTRY entries[count]; + } +}; + +struct PTABLE ptable; + +struct IMAGE_VERSION { + uchar major; + uchar minor; + uint16 revision; + uint32 build_num; +}; + +struct IHDR { + uint32 magic ; + uint32 load_addr ; + uint16 hdr_size ; + uint16 protect_size ; + uint32 img_size ; + uint32 flags; + struct IMAGE_VERSION ver; + uint32 _pad1; +}; + +struct TLV_HDR { + uint16 magic; + uint16 tlv_tot; +}; + +struct TLV { + uchar type ; + uchar pad; + uint16 len; + + switch (type) { + case 0x01: // keyhash + uchar keyhash[len]; + break; + case 0x40: // dependency + if (len != 12) { + Warning("Invalid dependency size"); + return -1; + } + uchar image_id; + uchar pad1; + uint16 pad2; + struct IMAGE_VERSION version; + break; + default: + // Other, just consume the data. + uchar data[len]; + } +}; + +local int i; +local int epos; + +for (i = 0; i < ptable.count; i++) { + FSeek(ptable.entries[i].offset); + switch (ptable.entries[i].id) { + case 1: + case 2: + case 4: + case 5: + struct IMAGE { + struct IHDR ihdr; + + if (ihdr.magic == 0x96f3b83d) { + uchar payload[ihdr.img_size]; + + epos = FTell(); + struct TLV_HDR tlv_hdr; + + if (tlv_hdr.magic == 0x6907) { + epos += tlv_hdr.tlv_tot; + while (FTell() < epos) { + struct TLV tlv; + } + } + } + // uchar block[ptable.entries[i].size]; + } image; + break; + case 3: + struct SCRATCH { + uchar data[ptable.entries[i].size]; + } scratch; + break; + default: + break; + } +} diff --git a/tools/mcuboot/requirements.txt b/tools/mcuboot/requirements.txt new file mode 100644 index 0000000..9481e2c --- /dev/null +++ b/tools/mcuboot/requirements.txt @@ -0,0 +1,4 @@ +cryptography>=2.6 +intelhex +click +cbor>=1.0.0 diff --git a/tools/mcuboot/setup.py b/tools/mcuboot/setup.py new file mode 100644 index 0000000..058d0cb --- /dev/null +++ b/tools/mcuboot/setup.py @@ -0,0 +1,29 @@ +import setuptools +from imgtool import imgtool_version + +setuptools.setup( + name="imgtool", + version=imgtool_version, + author="The MCUboot committers", + author_email="dev-mcuboot@lists.runtime.co", + description=("MCUboot's image signing and key management"), + license="Apache Software License", + url="http://github.com/JuulLabs-OSS/mcuboot", + packages=setuptools.find_packages(), + python_requires='>=3.6', + install_requires=[ + 'cryptography>=2.4.2', + 'intelhex>=2.2.1', + 'click', + 'cbor>=1.0.0', + ], + entry_points={ + "console_scripts": ["imgtool=imgtool.main:imgtool"] + }, + classifiers=[ + "Programming Language :: Python :: 3", + "Development Status :: 4 - Beta", + "Topic :: Software Development :: Build Tools", + "License :: OSI Approved :: Apache Software License", + ], +) From 6a8bd2090dc014417aaef356148a9b9b580eada4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 30 Nov 2024 00:36:51 +0100 Subject: [PATCH 06/21] Fix mcuboot --- .github/workflows/ci.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c8ff012..6a7ea28 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -49,22 +49,22 @@ jobs: uses: actions/upload-artifact@v3 with: name: watchful.bin - path: firmware/app/watchful.bin + path: firmware/watchful.bin - name: Upload HEX uses: actions/upload-artifact@v3 with: name: watchful.hex - path: firmware/app/watchful.hex + path: firmware/watchful.hex - name: Upload Mcuboot image uses: actions/upload-artifact@v3 with: name: watchful-image.bin - path: firmware/app/watchful-image.bin + path: firmware/watchful-image.bin - name: Upload DFU bundle uses: actions/upload-artifact@v3 with: name: watchful-dfu.zip - path: firmware/app/watchful-dfu.zip + path: firmware/watchful-dfu.zip From b5b3c31dfca97784cc564efe0aa48559e807bf15 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 30 Nov 2024 00:37:14 +0100 Subject: [PATCH 07/21] Disable watchdog --- firmware/src/main.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/firmware/src/main.rs b/firmware/src/main.rs index a358457..880a713 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -223,16 +223,6 @@ async fn main(s: Spawner) { } } -// Keeps our system alive -#[embassy_executor::task] -async fn watchdog_task() { - let mut handle = unsafe { embassy_nrf::wdt::WatchdogHandle::steal(0) }; - loop { - handle.pet(); - Timer::after(Duration::from_secs(4)).await; - } -} - #[derive(Clone)] pub struct DfuConfig<'a> { internal: &'a Mutex, From 32eea961bbde5dc6dc7a42328681342d0661f359 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 30 Nov 2024 00:50:59 +0100 Subject: [PATCH 08/21] Reenable watchdog --- firmware/src/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 880a713..c7c9e70 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -110,6 +110,7 @@ async fn main(s: Spawner) { SESSION_MEM.init(mpsl::SessionMem::new()) ))); s.must_spawn(mpsl_task(&*mpsl)); + s.must_spawn(watchdog_task()); let sdc_p = sdc::Peripherals::new( p.PPI_CH17, p.PPI_CH18, p.PPI_CH20, p.PPI_CH21, p.PPI_CH22, p.PPI_CH23, p.PPI_CH24, p.PPI_CH25, p.PPI_CH26, @@ -126,7 +127,7 @@ async fn main(s: Spawner) { let sdc = unwrap!(build_sdc(sdc_p, rng, mpsl, sdc_mem)); - s.spawn(clock(&CLOCK)).unwrap(); + s.must_spawn(clock(&CLOCK)); // Battery measurement let mut bat_config = saadc::ChannelConfig::single_ended(p.P0_31); @@ -223,6 +224,16 @@ async fn main(s: Spawner) { } } +// Keeps our system alive +#[embassy_executor::task] +async fn watchdog_task() { + let mut handle = unsafe { embassy_nrf::wdt::WatchdogHandle::steal(0) }; + loop { + handle.pet(); + Timer::after(Duration::from_secs(4)).await; + } +} + #[derive(Clone)] pub struct DfuConfig<'a> { internal: &'a Mutex, From d6c191971a9b2717936fbd932156cfd8617de732 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sun, 1 Dec 2024 08:17:19 +0100 Subject: [PATCH 09/21] Add recovery app --- infinitime-recovery/.cargo/config.toml | 21 + infinitime-recovery/Cargo.lock | 963 +++++++++++++++++++++++++ infinitime-recovery/Cargo.toml | 33 + infinitime-recovery/app/Cargo.toml | 23 + infinitime-recovery/app/build.rs | 37 + infinitime-recovery/app/memory.x | 6 + infinitime-recovery/app/src/main.rs | 110 +++ infinitime-recovery/boot/Cargo.toml | 12 + infinitime-recovery/boot/build.rs | 34 + infinitime-recovery/boot/memory.x | 10 + infinitime-recovery/boot/src/main.rs | 40 + 11 files changed, 1289 insertions(+) create mode 100644 infinitime-recovery/.cargo/config.toml create mode 100644 infinitime-recovery/Cargo.lock create mode 100644 infinitime-recovery/Cargo.toml create mode 100644 infinitime-recovery/app/Cargo.toml create mode 100644 infinitime-recovery/app/build.rs create mode 100644 infinitime-recovery/app/memory.x create mode 100644 infinitime-recovery/app/src/main.rs create mode 100644 infinitime-recovery/boot/Cargo.toml create mode 100644 infinitime-recovery/boot/build.rs create mode 100644 infinitime-recovery/boot/memory.x create mode 100644 infinitime-recovery/boot/src/main.rs diff --git a/infinitime-recovery/.cargo/config.toml b/infinitime-recovery/.cargo/config.toml new file mode 100644 index 0000000..85c2cad --- /dev/null +++ b/infinitime-recovery/.cargo/config.toml @@ -0,0 +1,21 @@ +[unstable] +build-std = ["core"] +build-std-features = ["panic_immediate_abort"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82832_xxAA with your chip as listed in `probe-rs-cli chip list` +#runner = "probe-rs-cli run --no-location --chip nRF52832_xxAA" +runner = "probe-run --chip nRF52832_xxAA" +rustflags = [ +# "-Z", "features=host_dep", + # Code-size optimizations. + "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", # try different values here + "-C", "no-vectorize-loops", # try with and without this +] + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "info" diff --git a/infinitime-recovery/Cargo.lock b/infinitime-recovery/Cargo.lock new file mode 100644 index 0000000..aa41972 --- /dev/null +++ b/infinitime-recovery/Cargo.lock @@ -0,0 +1,963 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atomic-polyfill" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +dependencies = [ + "critical-section", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version 0.2.3", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.29", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "document-features" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +dependencies = [ + "litrs", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca4a9380d03e61063067b8239f67d2fa9f108ede7c46b4273804f6b79e59a1d" +dependencies = [ + "embassy-futures", + "embassy-sync 0.5.0", + "embassy-time", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" +dependencies = [ + "embassy-futures", + "embassy-sync 0.6.1", + "embassy-time", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64f84599b0f4296b92a4b6ac2109bc02340094bda47b9766c5f9ec6a318ebf8" +dependencies = [ + "cortex-m", + "critical-section", + "document-features", + "embassy-executor-macros", + "embassy-time-driver", + "embassy-time-queue-driver", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "embassy-futures" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" + +[[package]] +name = "embassy-hal-internal" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0ec47cf8bab914018d4bd2b4f0aaeb46e4f52ab1e7985df88aeef2c6eda5aed" +dependencies = [ + "cortex-m", + "critical-section", + "num-traits", +] + +[[package]] +name = "embassy-hal-internal" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59" +dependencies = [ + "cortex-m", + "critical-section", + "num-traits", +] + +[[package]] +name = "embassy-nrf" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2faba661a13ac3417714ef23aa191af65941586dee692dbffe76ff7d3529321b" +dependencies = [ + "cfg-if", + "cortex-m", + "cortex-m-rt", + "critical-section", + "document-features", + "embassy-embedded-hal 0.1.0", + "embassy-hal-internal 0.1.0", + "embassy-sync 0.5.0", + "embassy-usb-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-io", + "embedded-io-async", + "embedded-storage", + "embedded-storage-async", + "fixed", + "nrf52805-pac", + "nrf52810-pac", + "nrf52811-pac", + "nrf52820-pac", + "nrf52832-pac", + "nrf52833-pac", + "nrf52840-pac", + "nrf5340-app-pac", + "nrf5340-net-pac", + "nrf9160-pac", + "rand_core", +] + +[[package]] +name = "embassy-nrf" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5f41f2ef4df68d3066c62667a0027b194cf6294e58afe8e6c36b8feede1e4ac" +dependencies = [ + "bitflags", + "cfg-if", + "cortex-m", + "cortex-m-rt", + "critical-section", + "document-features", + "embassy-embedded-hal 0.2.0", + "embassy-hal-internal 0.2.0", + "embassy-sync 0.6.1", + "embassy-time", + "embassy-time-driver", + "embassy-usb-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-io", + "embedded-io-async", + "embedded-storage", + "embedded-storage-async", + "fixed", + "nrf51-pac", + "nrf52805-pac", + "nrf52810-pac", + "nrf52811-pac", + "nrf52820-pac", + "nrf52832-pac", + "nrf52833-pac", + "nrf52840-pac", + "nrf5340-app-pac", + "nrf5340-net-pac", + "nrf9120-pac", + "nrf9160-pac", + "rand_core", +] + +[[package]] +name = "embassy-sync" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-util", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-sync" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3899a6e39fa3f54bf8aaf00979f9f9c0145a522f7244810533abbb748be6ce82" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-sink", + "futures-util", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embassy-time-queue-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-util", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time-driver" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24" +dependencies = [ + "document-features", +] + +[[package]] +name = "embassy-time-queue-driver" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0" + +[[package]] +name = "embassy-usb-driver" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc247028eae04174b6635104a35b1ed336aabef4654f5e87a8f32327d231970" + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "fixed" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "half" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill 0.1.11", + "hash32 0.2.1", + "rustc_version 0.4.0", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32 0.3.1", + "stable_deref_trait", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nrf51-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137f187dc6ee482e27312086bd3c3a83e1c273512782cf131a61957f72fc4219" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52805-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2da657648039d59f4de6bc31b948dd3a5d03b32529a4d5d19d9e2dd9d4bfa6c" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52810-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c26b12d5af17a9f4bb9a06ca9a1f814bca3d67bc8715b23f8dc230b09a227666" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52811-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4179b2a7ed0b2fd5e109d0fab9b4fc55b3936b2a4916a9306d22e5bc8dc1fd8f" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52820-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4791cff995e6419a5ad1aebc3b3c9539d79125ca85eb5bfd2cff9b470b81071" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52832-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0242b685c9c15648fb803e155628f42ace457478b2cb930868f40cae2db925e0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52833-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10e1358255b360cdc816dd7b6ef81be8c8499c0998277e5249bed222bd0f5241" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf52840-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf5340-app-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88824573cd150fe9f27c1a48cea31a8cb24d3322df488875775143618c087a" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf5340-net-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c03e44df22fe5888109fe42e523162c7059adf4d30860f4f73ecc8b1fc16fe" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf9120-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c012f18dc278aa33741722d374bc84e3d2d7694e29745f0bb83e56b2d6faf9b" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nrf9160-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7344d74afb5684e00c48d175cad9619f36d629cfb0687d33b4d1bb86fba688f4" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "reloader-bootloader" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "embassy-nrf 0.1.0", + "static_cell", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.18", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49cd323fc21eb534f903ee78d781d622099f9716c5b408ed23bcf39f8f1651c0" +dependencies = [ + "atomic-polyfill 1.0.3", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" +dependencies = [ + "vcell", +] + +[[package]] +name = "watchful-infinitime-recovery" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "embassy-embedded-hal 0.2.0", + "embassy-executor", + "embassy-futures", + "embassy-nrf 0.2.0", + "embassy-sync 0.6.1", + "embassy-time", + "embedded-hal 1.0.0", + "embedded-io", + "embedded-storage", + "futures", + "heapless 0.7.16", + "static_cell", +] diff --git a/infinitime-recovery/Cargo.toml b/infinitime-recovery/Cargo.toml new file mode 100644 index 0000000..0e8d8af --- /dev/null +++ b/infinitime-recovery/Cargo.toml @@ -0,0 +1,33 @@ +[workspace] +members = [ + "app", + "boot" +] + +resolver = "2" + +[patch.crates-io] +# embassy-executor = { path = "../../embassy/embassy-executor" } +# embassy-time = {path = "../../embassy/embassy-time"} +# embassy-sync = {path = "../../embassy/embassy-sync"} +# embassy-nrf = {path = "../../embassy/embassy-nrf"} +# embassy-embedded-hal = {path = "../../embassy/embassy-embedded-hal"} +# embassy-boot = {path = "../../embassy/embassy-boot/boot"} +# embassy-boot-nrf = {path = "../../embassy/embassy-boot/nrf"} +# embassy-futures = {path = "../../embassy/embassy-futures"} +#embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-boot = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-boot-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } +#embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } + +[profile.release] +debug = 2 +codegen-units = 1 +incremental = false +lto = "fat" +opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. + diff --git a/infinitime-recovery/app/Cargo.toml b/infinitime-recovery/app/Cargo.toml new file mode 100644 index 0000000..8434f1b --- /dev/null +++ b/infinitime-recovery/app/Cargo.toml @@ -0,0 +1,23 @@ +[package] +edition = "2021" +name = "watchful-infinitime-recovery" +version = "0.1.0" +license = "MIT OR Apache-2.0" +build = "build.rs" + +[dependencies] +embassy-futures = { version = "0.1.0" } +futures = { version = "0.3", default-features = false, features = ["async-await"]} +embassy-embedded-hal = { version = "0.2.0", default-features = false } +embassy-sync = { version = "0.6.0" } +embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "executor-interrupt"] } +embassy-time = { version = "0.3.0" } +embassy-nrf = { version = "0.2.0", features = ["nrf52832", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } +embedded-io = "0.6.0" +embedded-storage = "0.3.1" +embedded-hal = "1.0.0" + +static_cell = "1.1" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.3" +heapless = "0.7" diff --git a/infinitime-recovery/app/build.rs b/infinitime-recovery/app/build.rs new file mode 100644 index 0000000..1c10950 --- /dev/null +++ b/infinitime-recovery/app/build.rs @@ -0,0 +1,37 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rerun-if-changed=recovery.bin"); + println!("cargo:rerun-if-changed=mcuboot.bin"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); +} diff --git a/infinitime-recovery/app/memory.x b/infinitime-recovery/app/memory.x new file mode 100644 index 0000000..d57d1a9 --- /dev/null +++ b/infinitime-recovery/app/memory.x @@ -0,0 +1,6 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00039000, LENGTH = 324K + RAM : ORIGIN = 0x20000008, LENGTH = 32760 +} diff --git a/infinitime-recovery/app/src/main.rs b/infinitime-recovery/app/src/main.rs new file mode 100644 index 0000000..db5b1e7 --- /dev/null +++ b/infinitime-recovery/app/src/main.rs @@ -0,0 +1,110 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] + +use core::cell::RefCell; + +use embassy_embedded_hal::flash::partition::BlockingPartition; +use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; +use embassy_executor::{InterruptExecutor, Spawner}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::interrupt::{InterruptExt, Priority}; +use embassy_nrf::nvmc::Nvmc; +use embassy_nrf::spis::MODE_3; +use embassy_nrf::{bind_interrupts, interrupt, pac, peripherals, spim}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time::{Duration, Timer}; +use embedded_storage::nor_flash::NorFlash; + +static MCUBOOT: &[u8] = include_bytes!("../mcuboot.bin"); +static RECOVERY: &[u8] = include_bytes!("../recovery.bin"); + +const MCUBOOT_DEST: u32 = 0x00000000; +const RECOVERY_DEST: u32 = 0x00008000; + +#[interrupt] +unsafe fn SWI0_EGU0() { + EXECUTOR_MED.on_interrupt() +} + +static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); + +#[repr(align(4))] +struct AlignedBuffer([u8; 4096]); + +#[embassy_executor::main] +async fn main(s: Spawner) { + let p = embassy_nrf::init(Default::default()); + + // Medium-priority executor: SWI0_EGU0, priority level 7 + interrupt::SWI0_EGU0.set_priority(Priority::P6); + let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); + spawner.spawn(watchdog_task()).unwrap(); + + let mut led = Output::new(p.P0_22, Level::Low, OutputDrive::Standard); + + Timer::after(Duration::from_secs(1)).await; + + let mut buf = AlignedBuffer([0; 4096]); + let mut internal_flash = Nvmc::new(p.NVMC); + + internal_flash.erase(0, 0x8000).unwrap(); + Timer::after(Duration::from_secs(1)).await; + + let magic: &[u8] = &[ + 0xf3, 0x95, 0xc2, 0x77, 0x7f, 0xef, 0xd2, 0x60, 0x0f, 0x50, 0x52, 0x35, 0x80, 0x79, 0xb6, 0x2c, + ]; + let mut pos = MCUBOOT_DEST; + for chunk in MCUBOOT.chunks(4096) { + buf.0[..chunk.len()].copy_from_slice(chunk); + if chunk.len() < buf.0.len() { + for mut slice in buf.0[chunk.len()..].chunks_mut(magic.len()) { + let to_copy = slice.len(); + slice[0..to_copy].copy_from_slice(&magic[0..to_copy]); + } + } + + internal_flash.write(pos, &buf.0[..]).unwrap(); + pos += chunk.len() as u32; + Timer::after(Duration::from_millis(200)).await; + } + + for page in (0x8000..0x39000).step_by(4096) { + internal_flash.erase(page, 4096).unwrap(); + Timer::after(Duration::from_millis(200)).await; + } + + let mut pos = RECOVERY_DEST; + for chunk in RECOVERY.chunks(4096) { + buf.0[..chunk.len()].copy_from_slice(chunk); + if chunk.len() < buf.0.len() { + for mut slice in buf.0[chunk.len()..].chunks_mut(magic.len()) { + let to_copy = slice.len(); + slice[0..to_copy].copy_from_slice(&magic[0..to_copy]); + } + } + + internal_flash.write(pos, &buf.0[..]).unwrap(); + pos += chunk.len() as u32; + Timer::after(Duration::from_millis(200)).await; + } + Timer::after(Duration::from_secs(5)).await; + cortex_m::peripheral::SCB::sys_reset(); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + cortex_m::asm::udf(); +} + +// Keeps our system alive +#[embassy_executor::task] +async fn watchdog_task() { + let mut handle = unsafe { embassy_nrf::wdt::WatchdogHandle::steal(0) }; + loop { + handle.pet(); + Timer::after(Duration::from_secs(2)).await; + } +} diff --git a/infinitime-recovery/boot/Cargo.toml b/infinitime-recovery/boot/Cargo.toml new file mode 100644 index 0000000..2489bb3 --- /dev/null +++ b/infinitime-recovery/boot/Cargo.toml @@ -0,0 +1,12 @@ +[package] +edition = "2021" +name = "reloader-bootloader" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-nrf = { version = "0.1.0", default-features = false, features = ["rt", "nrf52832"] } + +static_cell = "1.1" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.3" diff --git a/infinitime-recovery/boot/build.rs b/infinitime-recovery/boot/build.rs new file mode 100644 index 0000000..cd1a264 --- /dev/null +++ b/infinitime-recovery/boot/build.rs @@ -0,0 +1,34 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); +} diff --git a/infinitime-recovery/boot/memory.x b/infinitime-recovery/boot/memory.x new file mode 100644 index 0000000..7c11a8d --- /dev/null +++ b/infinitime-recovery/boot/memory.x @@ -0,0 +1,10 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00026000, LENGTH = 16K + RELOADER : ORIGIN = 0x00039000, LENGTH = 284K + + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +__reloader_start = ORIGIN(RELOADER); diff --git a/infinitime-recovery/boot/src/main.rs b/infinitime-recovery/boot/src/main.rs new file mode 100644 index 0000000..1649d51 --- /dev/null +++ b/infinitime-recovery/boot/src/main.rs @@ -0,0 +1,40 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::{entry, exception}; +use embassy_nrf as _; + +#[entry] +fn main() -> ! { + unsafe { + extern "C" { + static __reloader_start: u32; + } + let start = &__reloader_start as *const u32 as u32; + + let mut p = cortex_m::Peripherals::steal(); + p.SCB.invalidate_icache(); + p.SCB.vtor.write(start); + + cortex_m::asm::bootload(start as *const u32) + } +} + +#[no_mangle] +#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +unsafe extern "C" fn HardFault() { + cortex_m::peripheral::SCB::sys_reset(); +} + +#[exception] +unsafe fn DefaultHandler(_: i16) -> ! { + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + + panic!("DefaultHandler #{:?}", irqn); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + cortex_m::asm::udf(); +} From 75c2ba6389804d64cb778daf1488cdb39210e023 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sun, 1 Dec 2024 08:17:33 +0100 Subject: [PATCH 10/21] Add script to build recovery app --- scripts/prepare_recovery.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 scripts/prepare_recovery.sh diff --git a/scripts/prepare_recovery.sh b/scripts/prepare_recovery.sh new file mode 100644 index 0000000..a453de5 --- /dev/null +++ b/scripts/prepare_recovery.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +#pushd infinitime-recovery/boot && cargo objcopy --release -- -O ihex ../../boot-recovery.hex && popd +#pushd infinitime-recovery/app && cargo objcopy --release -- -O ihex ../../app-recovery.hex && popd + +pushd blinky && cargo objcopy --release -- -O binary ../blinky.bin && popd + +#mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin + +imgtool create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header blinky.bin blinky-image.bin + +probe-rs erase --chip nRF52832_xxAA +probe-rs download blinky-image.bin --base-address 0x8000 --binary-format Binary --chip nRF52832_xxAA +probe-rs download bootloader-1.0.1.bin --base-address 0 --binary-format Binary --chip nRF52832_xxAA From 936a184aba4c46b636f5b78b5a83b42af4159346 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sun, 1 Dec 2024 09:03:47 +0100 Subject: [PATCH 11/21] Add unit test lib for recovery --- infinitime-recovery/Cargo.toml | 33 -- .../{ => app}/.cargo/config.toml | 0 infinitime-recovery/{ => app}/Cargo.lock | 293 ++++++------------ infinitime-recovery/app/Cargo.toml | 11 +- infinitime-recovery/app/src/main.rs | 73 +---- infinitime-recovery/boot/.cargo/config.toml | 21 ++ infinitime-recovery/boot/Cargo.toml | 8 + infinitime-recovery/recovery/Cargo.toml | 14 + infinitime-recovery/recovery/src/lib.rs | 211 +++++++++++++ scripts/prepare_recovery.sh | 16 +- 10 files changed, 387 insertions(+), 293 deletions(-) delete mode 100644 infinitime-recovery/Cargo.toml rename infinitime-recovery/{ => app}/.cargo/config.toml (100%) rename infinitime-recovery/{ => app}/Cargo.lock (76%) create mode 100644 infinitime-recovery/boot/.cargo/config.toml create mode 100644 infinitime-recovery/recovery/Cargo.toml create mode 100644 infinitime-recovery/recovery/src/lib.rs diff --git a/infinitime-recovery/Cargo.toml b/infinitime-recovery/Cargo.toml deleted file mode 100644 index 0e8d8af..0000000 --- a/infinitime-recovery/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[workspace] -members = [ - "app", - "boot" -] - -resolver = "2" - -[patch.crates-io] -# embassy-executor = { path = "../../embassy/embassy-executor" } -# embassy-time = {path = "../../embassy/embassy-time"} -# embassy-sync = {path = "../../embassy/embassy-sync"} -# embassy-nrf = {path = "../../embassy/embassy-nrf"} -# embassy-embedded-hal = {path = "../../embassy/embassy-embedded-hal"} -# embassy-boot = {path = "../../embassy/embassy-boot/boot"} -# embassy-boot-nrf = {path = "../../embassy/embassy-boot/nrf"} -# embassy-futures = {path = "../../embassy/embassy-futures"} -#embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-boot = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-boot-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -#embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } - -[profile.release] -debug = 2 -codegen-units = 1 -incremental = false -lto = "fat" -opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. - diff --git a/infinitime-recovery/.cargo/config.toml b/infinitime-recovery/app/.cargo/config.toml similarity index 100% rename from infinitime-recovery/.cargo/config.toml rename to infinitime-recovery/app/.cargo/config.toml diff --git a/infinitime-recovery/Cargo.lock b/infinitime-recovery/app/Cargo.lock similarity index 76% rename from infinitime-recovery/Cargo.lock rename to infinitime-recovery/app/Cargo.lock index aa41972..210d190 100644 --- a/infinitime-recovery/Cargo.lock +++ b/infinitime-recovery/app/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "atomic-polyfill" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -22,9 +13,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "az" @@ -55,15 +46,15 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cfg-if" @@ -86,29 +77,29 @@ dependencies = [ [[package]] name = "cortex-m-rt" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" dependencies = [ "cortex-m-rt-macros", ] [[package]] name = "cortex-m-rt-macros" -version = "0.7.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "critical-section" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crunchy" @@ -118,9 +109,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -128,27 +119,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.29", + "syn", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.29", + "syn", ] [[package]] @@ -160,23 +151,6 @@ dependencies = [ "litrs", ] -[[package]] -name = "embassy-embedded-hal" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca4a9380d03e61063067b8239f67d2fa9f108ede7c46b4273804f6b79e59a1d" -dependencies = [ - "embassy-futures", - "embassy-sync 0.5.0", - "embassy-time", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-storage", - "embedded-storage-async", - "nb 1.1.0", -] - [[package]] name = "embassy-embedded-hal" version = "0.2.0" @@ -184,7 +158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" dependencies = [ "embassy-futures", - "embassy-sync 0.6.1", + "embassy-sync", "embassy-time", "embedded-hal 0.2.7", "embedded-hal 1.0.0", @@ -217,7 +191,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.29", + "syn", ] [[package]] @@ -226,17 +200,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" -[[package]] -name = "embassy-hal-internal" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ec47cf8bab914018d4bd2b4f0aaeb46e4f52ab1e7985df88aeef2c6eda5aed" -dependencies = [ - "cortex-m", - "critical-section", - "num-traits", -] - [[package]] name = "embassy-hal-internal" version = "0.2.0" @@ -248,42 +211,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "embassy-nrf" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faba661a13ac3417714ef23aa191af65941586dee692dbffe76ff7d3529321b" -dependencies = [ - "cfg-if", - "cortex-m", - "cortex-m-rt", - "critical-section", - "document-features", - "embassy-embedded-hal 0.1.0", - "embassy-hal-internal 0.1.0", - "embassy-sync 0.5.0", - "embassy-usb-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-io", - "embedded-io-async", - "embedded-storage", - "embedded-storage-async", - "fixed", - "nrf52805-pac", - "nrf52810-pac", - "nrf52811-pac", - "nrf52820-pac", - "nrf52832-pac", - "nrf52833-pac", - "nrf52840-pac", - "nrf5340-app-pac", - "nrf5340-net-pac", - "nrf9160-pac", - "rand_core", -] - [[package]] name = "embassy-nrf" version = "0.2.0" @@ -296,9 +223,9 @@ dependencies = [ "cortex-m-rt", "critical-section", "document-features", - "embassy-embedded-hal 0.2.0", - "embassy-hal-internal 0.2.0", - "embassy-sync 0.6.1", + "embassy-embedded-hal", + "embassy-hal-internal", + "embassy-sync", "embassy-time", "embassy-time-driver", "embassy-usb-driver", @@ -325,19 +252,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "embassy-sync" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-util", - "heapless 0.8.0", -] - [[package]] name = "embassy-sync" version = "0.6.1" @@ -448,9 +362,9 @@ dependencies = [ [[package]] name = "fixed" -version = "1.23.1" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9" +checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" dependencies = [ "az", "bytemuck", @@ -466,9 +380,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -480,9 +394,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -490,44 +404,44 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", @@ -539,9 +453,9 @@ dependencies = [ [[package]] name = "half" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -567,13 +481,13 @@ dependencies = [ [[package]] name = "heapless" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ - "atomic-polyfill 0.1.11", + "atomic-polyfill", "hash32 0.2.1", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "spin", "stable_deref_trait", ] @@ -602,9 +516,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -759,18 +673,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -778,20 +692,29 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +dependencies = [ + "critical-section", +] + [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -802,16 +725,6 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -[[package]] -name = "reloader-bootloader" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "embassy-nrf 0.1.0", - "static_cell", -] - [[package]] name = "rustc_version" version = "0.2.3" @@ -823,11 +736,11 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.18", + "semver 1.0.23", ] [[package]] @@ -847,9 +760,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "semver-parser" @@ -874,35 +787,24 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_cell" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cd323fc21eb534f903ee78d781d622099f9716c5b408ed23bcf39f8f1651c0" +checksum = "2cd3f559c6c41cde362aed95cd84765907e06057f087b17269b41750ec40a3e7" dependencies = [ - "atomic-polyfill 1.0.3", + "portable-atomic", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.29" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -911,15 +813,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "vcell" @@ -935,9 +837,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "volatile-register" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" dependencies = [ "vcell", ] @@ -945,19 +847,30 @@ dependencies = [ [[package]] name = "watchful-infinitime-recovery" version = "0.1.0" +dependencies = [ + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-io", + "embedded-storage", +] + +[[package]] +name = "watchful-infinitime-recovery-app" +version = "0.1.0" dependencies = [ "cortex-m", "cortex-m-rt", - "embassy-embedded-hal 0.2.0", + "embassy-embedded-hal", "embassy-executor", "embassy-futures", - "embassy-nrf 0.2.0", - "embassy-sync 0.6.1", + "embassy-nrf", + "embassy-sync", "embassy-time", "embedded-hal 1.0.0", "embedded-io", "embedded-storage", "futures", - "heapless 0.7.16", + "heapless 0.7.17", "static_cell", + "watchful-infinitime-recovery", ] diff --git a/infinitime-recovery/app/Cargo.toml b/infinitime-recovery/app/Cargo.toml index 8434f1b..e1cec12 100644 --- a/infinitime-recovery/app/Cargo.toml +++ b/infinitime-recovery/app/Cargo.toml @@ -1,9 +1,10 @@ [package] edition = "2021" -name = "watchful-infinitime-recovery" +name = "watchful-infinitime-recovery-app" version = "0.1.0" license = "MIT OR Apache-2.0" build = "build.rs" +resolver = "2" [dependencies] embassy-futures = { version = "0.1.0" } @@ -16,8 +17,16 @@ embassy-nrf = { version = "0.2.0", features = ["nrf52832", "time-driver-rtc1", " embedded-io = "0.6.0" embedded-storage = "0.3.1" embedded-hal = "1.0.0" +watchful-infinitime-recovery = { path = "../recovery" } static_cell = "1.1" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.3" heapless = "0.7" + +[profile.release] +debug = 2 +codegen-units = 1 +incremental = false +lto = "fat" +opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. diff --git a/infinitime-recovery/app/src/main.rs b/infinitime-recovery/app/src/main.rs index db5b1e7..db5ebdd 100644 --- a/infinitime-recovery/app/src/main.rs +++ b/infinitime-recovery/app/src/main.rs @@ -3,39 +3,27 @@ #![feature(type_alias_impl_trait)] #![feature(impl_trait_in_assoc_type)] -use core::cell::RefCell; - -use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::{InterruptExecutor, Spawner}; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::interrupt; use embassy_nrf::interrupt::{InterruptExt, Priority}; use embassy_nrf::nvmc::Nvmc; -use embassy_nrf::spis::MODE_3; -use embassy_nrf::{bind_interrupts, interrupt, pac, peripherals, spim}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::blocking_mutex::Mutex; use embassy_time::{Duration, Timer}; -use embedded_storage::nor_flash::NorFlash; - -static MCUBOOT: &[u8] = include_bytes!("../mcuboot.bin"); -static RECOVERY: &[u8] = include_bytes!("../recovery.bin"); - -const MCUBOOT_DEST: u32 = 0x00000000; -const RECOVERY_DEST: u32 = 0x00008000; #[interrupt] unsafe fn SWI0_EGU0() { EXECUTOR_MED.on_interrupt() } +static MCUBOOT: &[u8] = include_bytes!("../mcuboot.bin"); +static RECOVERY: &[u8] = include_bytes!("../recovery.bin"); + static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); #[repr(align(4))] struct AlignedBuffer([u8; 4096]); #[embassy_executor::main] -async fn main(s: Spawner) { +async fn main(_s: Spawner) { let p = embassy_nrf::init(Default::default()); // Medium-priority executor: SWI0_EGU0, priority level 7 @@ -43,53 +31,18 @@ async fn main(s: Spawner) { let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); spawner.spawn(watchdog_task()).unwrap(); - let mut led = Output::new(p.P0_22, Level::Low, OutputDrive::Standard); - Timer::after(Duration::from_secs(1)).await; let mut buf = AlignedBuffer([0; 4096]); let mut internal_flash = Nvmc::new(p.NVMC); - - internal_flash.erase(0, 0x8000).unwrap(); - Timer::after(Duration::from_secs(1)).await; - - let magic: &[u8] = &[ - 0xf3, 0x95, 0xc2, 0x77, 0x7f, 0xef, 0xd2, 0x60, 0x0f, 0x50, 0x52, 0x35, 0x80, 0x79, 0xb6, 0x2c, - ]; - let mut pos = MCUBOOT_DEST; - for chunk in MCUBOOT.chunks(4096) { - buf.0[..chunk.len()].copy_from_slice(chunk); - if chunk.len() < buf.0.len() { - for mut slice in buf.0[chunk.len()..].chunks_mut(magic.len()) { - let to_copy = slice.len(); - slice[0..to_copy].copy_from_slice(&magic[0..to_copy]); - } - } - - internal_flash.write(pos, &buf.0[..]).unwrap(); - pos += chunk.len() as u32; - Timer::after(Duration::from_millis(200)).await; - } - - for page in (0x8000..0x39000).step_by(4096) { - internal_flash.erase(page, 4096).unwrap(); - Timer::after(Duration::from_millis(200)).await; - } - - let mut pos = RECOVERY_DEST; - for chunk in RECOVERY.chunks(4096) { - buf.0[..chunk.len()].copy_from_slice(chunk); - if chunk.len() < buf.0.len() { - for mut slice in buf.0[chunk.len()..].chunks_mut(magic.len()) { - let to_copy = slice.len(); - slice[0..to_copy].copy_from_slice(&magic[0..to_copy]); - } - } - - internal_flash.write(pos, &buf.0[..]).unwrap(); - pos += chunk.len() as u32; - Timer::after(Duration::from_millis(200)).await; - } + watchful_infinitime_recovery::recover( + &mut internal_flash, + &mut embassy_time::Delay, + &mut buf.0, + MCUBOOT, + RECOVERY, + ) + .await; Timer::after(Duration::from_secs(5)).await; cortex_m::peripheral::SCB::sys_reset(); } diff --git a/infinitime-recovery/boot/.cargo/config.toml b/infinitime-recovery/boot/.cargo/config.toml new file mode 100644 index 0000000..85c2cad --- /dev/null +++ b/infinitime-recovery/boot/.cargo/config.toml @@ -0,0 +1,21 @@ +[unstable] +build-std = ["core"] +build-std-features = ["panic_immediate_abort"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82832_xxAA with your chip as listed in `probe-rs-cli chip list` +#runner = "probe-rs-cli run --no-location --chip nRF52832_xxAA" +runner = "probe-run --chip nRF52832_xxAA" +rustflags = [ +# "-Z", "features=host_dep", + # Code-size optimizations. + "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", # try different values here + "-C", "no-vectorize-loops", # try with and without this +] + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "info" diff --git a/infinitime-recovery/boot/Cargo.toml b/infinitime-recovery/boot/Cargo.toml index 2489bb3..33d7967 100644 --- a/infinitime-recovery/boot/Cargo.toml +++ b/infinitime-recovery/boot/Cargo.toml @@ -3,6 +3,7 @@ edition = "2021" name = "reloader-bootloader" version = "0.1.0" license = "MIT OR Apache-2.0" +resolver = "2" [dependencies] embassy-nrf = { version = "0.1.0", default-features = false, features = ["rt", "nrf52832"] } @@ -10,3 +11,10 @@ embassy-nrf = { version = "0.1.0", default-features = false, features = ["rt", " static_cell = "1.1" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.3" + +[profile.release] +debug = 2 +codegen-units = 1 +incremental = false +lto = "fat" +opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. diff --git a/infinitime-recovery/recovery/Cargo.toml b/infinitime-recovery/recovery/Cargo.toml new file mode 100644 index 0000000..6f4867a --- /dev/null +++ b/infinitime-recovery/recovery/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "watchful-infinitime-recovery" +version = "0.1.0" +license = "MIT OR Apache-2.0" +edition = "2021" + +[dependencies] +embedded-hal-async = "1.0.0" +embedded-io = "0.6.0" +embedded-storage = "0.3.1" +embedded-hal = "1.0.0" + +[dev-dependencies] +futures-test = "0.3" diff --git a/infinitime-recovery/recovery/src/lib.rs b/infinitime-recovery/recovery/src/lib.rs new file mode 100644 index 0000000..26cd9b8 --- /dev/null +++ b/infinitime-recovery/recovery/src/lib.rs @@ -0,0 +1,211 @@ +#![no_std] + +use embedded_hal_async::delay::DelayNs; +use embedded_storage::nor_flash::NorFlash; + +const MCUBOOT_DEST: u32 = 0x00000000; +const RECOVERY_DEST: u32 = 0x00008000; + +pub async fn recover( + flash: &mut N, + delay: &mut D, + buf: &mut [u8], + mcuboot: &[u8], + recovery: &[u8], +) { + flash.erase(0, 0x8000).unwrap(); + delay.delay_ms(1000).await; + + let magic: &[u8] = &[ + 0xf3, 0x95, 0xc2, 0x77, 0x7f, 0xef, 0xd2, 0x60, 0x0f, 0x50, 0x52, 0x35, 0x80, 0x79, 0xb6, 0x2c, + ]; + let mut pos = MCUBOOT_DEST; + for chunk in mcuboot.chunks(4096) { + buf[..chunk.len()].copy_from_slice(chunk); + if chunk.len() < buf.len() { + for slice in buf[chunk.len()..].chunks_mut(magic.len()) { + let to_copy = slice.len(); + slice[0..to_copy].copy_from_slice(&magic[0..to_copy]); + } + } + + flash.write(pos, &buf[..]).unwrap(); + pos += chunk.len() as u32; + delay.delay_ms(100).await; + } + + for page in (0x8000..0x39000).step_by(4096) { + flash.erase(page, page + 4096).unwrap(); + delay.delay_ms(100).await; + } + + let mut pos = RECOVERY_DEST; + for chunk in recovery.chunks(4096) { + buf[..chunk.len()].copy_from_slice(chunk); + if chunk.len() < buf.len() { + for slice in buf[chunk.len()..].chunks_mut(magic.len()) { + let to_copy = slice.len(); + slice[0..to_copy].copy_from_slice(&magic[0..to_copy]); + } + } + + flash.write(pos, &buf[..]).unwrap(); + pos += chunk.len() as u32; + delay.delay_ms(100).await; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[futures_test::test] + async fn test_recovery() { + const SIZE: usize = 512 * 1024; + let mut mem_flash: MemFlash = MemFlash::new(0xFF); + + let mcuboot: [u8; 14555] = [0x42; 14555]; + let recovery: [u8; 68832] = [0x33; 68832]; + + #[repr(align(4))] + struct AlignedBuffer([u8; 4096]); + + let mut buf = AlignedBuffer([0; 4096]); + let mut t = TestTimer; + recover(&mut mem_flash, &mut t, &mut buf.0, &mcuboot[..], &recovery[..]).await; + assert_eq!(&mem_flash.mem[..14555], mcuboot); + assert_eq!(&mem_flash.mem[0x8000..0x8000 + recovery.len()], recovery); + } + + struct TestTimer; + impl embedded_hal_async::delay::DelayNs for TestTimer { + async fn delay_ns(&mut self, _d: u32) {} + } + + use core::ops::{Bound, Range, RangeBounds}; + + use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; + + pub struct MemFlash { + pub mem: [u8; SIZE], + pub pending_write_successes: Option, + } + + #[derive(Debug)] + pub struct MemFlashError; + + impl MemFlash { + pub const fn new(fill: u8) -> Self { + Self { + mem: [fill; SIZE], + pending_write_successes: None, + } + } + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), MemFlashError> { + let len = bytes.len(); + bytes.copy_from_slice(&self.mem[offset as usize..offset as usize + len]); + Ok(()) + } + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), MemFlashError> { + let offset = offset as usize; + assert!(bytes.len() % WRITE_SIZE == 0); + assert!(offset % WRITE_SIZE == 0); + assert!(offset + bytes.len() <= SIZE); + + if let Some(pending_successes) = self.pending_write_successes { + if pending_successes > 0 { + self.pending_write_successes = Some(pending_successes - 1); + } else { + return Err(MemFlashError); + } + } + + for ((offset, mem_byte), new_byte) in self + .mem + .iter_mut() + .enumerate() + .skip(offset) + .take(bytes.len()) + .zip(bytes) + { + assert_eq!(0xFF, *mem_byte, "Offset {} is not erased", offset); + *mem_byte = *new_byte; + } + + Ok(()) + } + + fn erase(&mut self, from: u32, to: u32) -> Result<(), MemFlashError> { + let from = from as usize; + let to = to as usize; + assert!(from % ERASE_SIZE == 0); + assert!(to % ERASE_SIZE == 0, "To: {}, erase size: {}", to, ERASE_SIZE); + for i in from..to { + self.mem[i] = 0xFF; + } + Ok(()) + } + + pub fn program(&mut self, offset: u32, bytes: &[u8]) -> Result<(), MemFlashError> { + let offset = offset as usize; + assert!(bytes.len() % WRITE_SIZE == 0); + assert!(offset % WRITE_SIZE == 0); + assert!(offset + bytes.len() <= SIZE); + + self.mem[offset..offset + bytes.len()].copy_from_slice(bytes); + + Ok(()) + } + } + + impl Default + for MemFlash + { + fn default() -> Self { + Self::new(0xFF) + } + } + + impl ErrorType + for MemFlash + { + type Error = MemFlashError; + } + + impl NorFlashError for MemFlashError { + fn kind(&self) -> NorFlashErrorKind { + NorFlashErrorKind::Other + } + } + + impl ReadNorFlash + for MemFlash + { + const READ_SIZE: usize = 1; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.read(offset, bytes) + } + + fn capacity(&self) -> usize { + SIZE + } + } + + impl NorFlash + for MemFlash + { + const WRITE_SIZE: usize = WRITE_SIZE; + const ERASE_SIZE: usize = ERASE_SIZE; + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(offset, bytes) + } + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.erase(from, to) + } + } +} diff --git a/scripts/prepare_recovery.sh b/scripts/prepare_recovery.sh index a453de5..ff737a1 100644 --- a/scripts/prepare_recovery.sh +++ b/scripts/prepare_recovery.sh @@ -1,14 +1,12 @@ #!/usr/bin/env sh -#pushd infinitime-recovery/boot && cargo objcopy --release -- -O ihex ../../boot-recovery.hex && popd -#pushd infinitime-recovery/app && cargo objcopy --release -- -O ihex ../../app-recovery.hex && popd +pushd infinitime-recovery/boot && cargo objcopy --release -- -O ihex ../../boot-recovery.hex && popd +pushd infinitime-recovery/app && cargo objcopy --release -- -O ihex ../../app-recovery.hex && popd -pushd blinky && cargo objcopy --release -- -O binary ../blinky.bin && popd +mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin -#mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin +imgtool create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header infinitime-recovery.bin infinitime-recovery-image.bin -imgtool create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header blinky.bin blinky-image.bin - -probe-rs erase --chip nRF52832_xxAA -probe-rs download blinky-image.bin --base-address 0x8000 --binary-format Binary --chip nRF52832_xxAA -probe-rs download bootloader-1.0.1.bin --base-address 0 --binary-format Binary --chip nRF52832_xxAA +#probe-rs erase --chip nRF52832_xxAA +#probe-rs download blinky-image.bin --base-address 0x8000 --binary-format Binary --chip nRF52832_xxAA +#probe-rs download bootloader-1.0.1.bin --base-address 0 --binary-format Binary --chip nRF52832_xxAA From 3743e94230b591f89687872f2f2dc11a8878493d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sun, 1 Dec 2024 09:06:50 +0100 Subject: [PATCH 12/21] Fixup imgtool --- infinitime-recovery/app/.cargo/config.toml | 1 - infinitime-recovery/boot/.cargo/config.toml | 1 - scripts/prepare_recovery.sh | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) mode change 100644 => 100755 scripts/prepare_recovery.sh diff --git a/infinitime-recovery/app/.cargo/config.toml b/infinitime-recovery/app/.cargo/config.toml index 85c2cad..47b0cea 100644 --- a/infinitime-recovery/app/.cargo/config.toml +++ b/infinitime-recovery/app/.cargo/config.toml @@ -10,7 +10,6 @@ rustflags = [ # "-Z", "features=host_dep", # Code-size optimizations. "-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", # try different values here "-C", "no-vectorize-loops", # try with and without this ] diff --git a/infinitime-recovery/boot/.cargo/config.toml b/infinitime-recovery/boot/.cargo/config.toml index 85c2cad..47b0cea 100644 --- a/infinitime-recovery/boot/.cargo/config.toml +++ b/infinitime-recovery/boot/.cargo/config.toml @@ -10,7 +10,6 @@ rustflags = [ # "-Z", "features=host_dep", # Code-size optimizations. "-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", # try different values here "-C", "no-vectorize-loops", # try with and without this ] diff --git a/scripts/prepare_recovery.sh b/scripts/prepare_recovery.sh old mode 100644 new mode 100755 index ff737a1..56a92f8 --- a/scripts/prepare_recovery.sh +++ b/scripts/prepare_recovery.sh @@ -5,7 +5,7 @@ pushd infinitime-recovery/app && cargo objcopy --release -- -O ihex ../../app-re mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin -imgtool create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header infinitime-recovery.bin infinitime-recovery-image.bin +tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header infinitime-recovery.bin infinitime-recovery-image.bin #probe-rs erase --chip nRF52832_xxAA #probe-rs download blinky-image.bin --base-address 0x8000 --binary-format Binary --chip nRF52832_xxAA From 181e2cd1822f54872243596876587bca9081faf8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 11 Dec 2024 22:36:23 +0100 Subject: [PATCH 13/21] Fixes --- README.md | 28 +++++++++---------- firmware/.cargo/config.toml | 2 +- firmware/Cargo.toml | 9 ++++-- firmware/build.rs | 9 +++++- firmware/memory.x | 1 + firmware/src/ble.rs | 4 +-- firmware/src/main.rs | 13 +++++---- infinitime-recovery/app/Cargo.lock | 42 ++++++++++++++-------------- infinitime-recovery/app/Cargo.toml | 2 +- infinitime-recovery/app/memory.x | 4 +-- infinitime-recovery/app/src/main.rs | 30 ++++++++++++-------- infinitime-recovery/boot/Cargo.toml | 2 +- infinitime-recovery/boot/memory.x | 2 +- infinitime-recovery/boot/src/main.rs | 2 +- scripts/flash_infinitime.sh | 4 +-- scripts/prepare.sh | 4 +-- scripts/prepare_recovery.sh | 12 ++++++-- 17 files changed, 98 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 9bcfd7f..38231d9 100644 --- a/README.md +++ b/README.md @@ -12,34 +12,32 @@ Firmware for Pinetime based on [Embassy](https://embassy.dev). The goal is to pr ## Features -* Implements Nordic DFU protocol so you can update from a phone app such as nRF Connect. +* Basic UI with menus using [`embedded-graphics`](https://crates.io/crates/embedded-graphics). +* Implements Nordic DFU protocol so you can update from a phone app such as nRF Connect to perform firmware updates. * Automatically synchronizes time with using BLE standard Current Time Service. -* Use external flash (4MB) for firmware updates and persistence. * Rollback to previous firmware if reset or crashing before new firmware is validated in watch UI. -* Can be installed from Infinitime using DFU. +* Compatible with existing InfiniTime bootloader. ## Getting started -The recommended way to run Watchful is to get a [PineTime Development Kit](https://pine64.com/product/pinetime-dev-kit/), to which you can connect a debug probe. To run Watchful, you need to download the latest [S132 SoftDevice](https://www.nordicsemi.com/Products/Development-software/s132/download). For flashing and running with the debug probe, `probe-rs` is recommended. +If you have InfiniTime running already, it's easy to try out Watchful. You can use the same app you use to update InfiniTime to try out Watchful (such as GadgetBridge). -To run Watchful: +Pick the `watchful-dfu.zip` from the [latest release](https://github.com/lulf/watchful/releases) and upload it to your watch. To revert back to InfiniTime, head into the menu -> settings -> reset, and mcuboot will do the rest. -``` 4d -# Installing the softdevice -probe-rs download path-to-softdevice.hex --format Hex --chip nRF52832_xxAA +## Developing -# Flashing the bootloader -cd firmware/boot -cargo flash --release +The recommended way to develop Watchful is to get a [PineTime Development Kit](https://pine64.com/product/pinetime-dev-kit/), to which you can connect a debug probe. For flashing and running with the debug probe, `probe-rs` is recommended. -# Flashing the OS -cd ../app -cargo flash --release +To run Watchful: + +``` 4d +cd firmware +cargo run --release --features panic-probe,baremetal ``` ## Updating firmware -Once you have Watchful running, you can use an app such as nRF Connect on Android or iOS using the DFU functionality with the [latest release](https://github.com/lulf/watchful/releases). +Once you have Watchful running, you can use an app such as GadgetBridge nRF Connect on Android or iOS using the DFU functionality with the [latest release](https://github.com/lulf/watchful/releases). ## *DANGER* Reflashing your sealed PineTime from InfiniTime to Watchful diff --git a/firmware/.cargo/config.toml b/firmware/.cargo/config.toml index 90c4c42..ddd65a1 100644 --- a/firmware/.cargo/config.toml +++ b/firmware/.cargo/config.toml @@ -5,7 +5,7 @@ build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace nRF82832_xxAA with your chip as listed in `probe-rs-cli chip list` #runner = "probe-rs-cli run --no-location --chip nRF52832_xxAA" -runner = "probe-run --chip nRF52832_xxAA" +runner = "probe-rs run --chip nRF52832_xxAA" [build] target = "thumbv7em-none-eabi" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index cb88a33..8d1967b 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -11,9 +11,9 @@ embassy-futures = { version = "0.1" } futures = { version = "0.3", default-features = false, features = ["async-await"]} embassy-embedded-hal = { version = "0.2", default-features = false } embassy-sync = { version = "0.6" } -embassy-executor = { version = "0.6", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-nrf = { version = "0.2", features = ["defmt", "nrf52832", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } +embassy-executor = { version = "0.6", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers", "task-arena-size-8192"] } +embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.2", features = ["defmt", "nrf52832", "time-driver-rtc1", "rt", "gpiote", "unstable-pac", "time", "nfc-pins-as-gpio"] } embedded-io = "0.6" embedded-io-async = "0.6" embedded-storage = "0.3" @@ -46,6 +46,9 @@ display-interface-spi = "0.5" time = { version = "0.3.24", default-features = false } byte-slice-cast = { version = "1.2.0", default-features = false } +[features] +baremetal = [] + [build-dependencies] vergen = { version = "8", features = ["build", "git", "gitcl"] } diff --git a/firmware/build.rs b/firmware/build.rs index c2843d3..ded35b2 100644 --- a/firmware/build.rs +++ b/firmware/build.rs @@ -15,13 +15,20 @@ use std::path::PathBuf; use vergen::EmitBuilder; +fn linker_data() -> &'static [u8] { + #[cfg(feature = "baremetal")] + return include_bytes!("memory-bm.x"); + #[cfg(not(feature = "baremetal"))] + return include_bytes!("memory.x"); +} + fn main() { // Put `memory.x` in our output directory and ensure it's // on the linker search path. let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("memory.x")) .unwrap() - .write_all(include_bytes!("memory.x")) + .write_all(linker_data()) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); diff --git a/firmware/memory.x b/firmware/memory.x index c62110a..edecee9 100644 --- a/firmware/memory.x +++ b/firmware/memory.x @@ -2,5 +2,6 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ FLASH : ORIGIN = 0x00008020, LENGTH = 256K + /*FLASH : ORIGIN = 0x00000000, LENGTH = 256K */ RAM : ORIGIN = 0x20000008, LENGTH = 32760 } diff --git a/firmware/src/ble.rs b/firmware/src/ble.rs index d427be1..818b4d9 100644 --- a/firmware/src/ble.rs +++ b/firmware/src/ble.rs @@ -153,8 +153,8 @@ impl PineTimeServer<'_, '_, NrfController> { } /// Size of L2CAP packets (ATT MTU is this - 4) -const L2CAP_MTU: usize = 251; -const CONNECTIONS_MAX: usize = 2; +const L2CAP_MTU: usize = 27; +const CONNECTIONS_MAX: usize = 1; const L2CAP_CHANNELS_MAX: usize = 2; // Signal + att type BleResources = HostResources; static RESOURCES: StaticCell = StaticCell::new(); diff --git a/firmware/src/main.rs b/firmware/src/main.rs index c7c9e70..bfadccc 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -119,7 +119,7 @@ async fn main(s: Spawner) { let rng = rng::Rng::new(p.RNG, Irqs); - static SDC_MEM: StaticCell> = StaticCell::new(); + static SDC_MEM: StaticCell> = StaticCell::new(); let sdc_mem = SDC_MEM.init(sdc::Mem::new()); static RNG: StaticCell> = StaticCell::new(); @@ -185,10 +185,11 @@ async fn main(s: Spawner) { let dfu_config = DfuConfig::new(internal_flash, external_flash); // BLE - ble::start(s, sdc, dfu_config); + // ble::start(s, sdc, dfu_config); // Display - let backlight = Output::new(p.P0_22.degrade(), Level::Low, OutputDrive::Standard); // Medium backlight + + let mut backlight = Output::new(p.P0_22.degrade(), Level::Low, OutputDrive::Standard); // Medium backlight let rst = Output::new(p.P0_26, Level::Low, OutputDrive::Standard); let display_cs = Output::new(p.P0_25, Level::High, OutputDrive::Standard); // Keep low while driving display let display_spi = SpiDevice::new(spi_bus, display_cs); @@ -202,6 +203,8 @@ async fn main(s: Spawner) { .unwrap(); display.set_orientation(Orientation::new()).unwrap(); + backlight.set_high(); + let screen = Screen::new(display, backlight); let mut device: Device<'_> = Device { clock: &CLOCK, @@ -253,12 +256,12 @@ impl<'a> DfuConfig<'a> { let dfu_start = u32::MAX; let dfu_end = u32::MAX; - BlockingPartition::new(external, dfu_start, dfu_end - dfu_start); + //BlockingPartition::new(external, dfu_start, dfu_end - dfu_start); let state_start = u32::MAX; let state_end = u32::MAX; - Partition::new(internal, state_start, state_end - state_start); + //Partition::new(internal, state_start, state_end - state_start); Self { internal, external, diff --git a/infinitime-recovery/app/Cargo.lock b/infinitime-recovery/app/Cargo.lock index 210d190..df6313e 100644 --- a/infinitime-recovery/app/Cargo.lock +++ b/infinitime-recovery/app/Cargo.lock @@ -725,6 +725,27 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "recovery-app" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "embassy-embedded-hal", + "embassy-executor", + "embassy-futures", + "embassy-nrf", + "embassy-sync", + "embassy-time", + "embedded-hal 1.0.0", + "embedded-io", + "embedded-storage", + "futures", + "heapless 0.7.17", + "static_cell", + "watchful-infinitime-recovery", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -853,24 +874,3 @@ dependencies = [ "embedded-io", "embedded-storage", ] - -[[package]] -name = "watchful-infinitime-recovery-app" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "embassy-embedded-hal", - "embassy-executor", - "embassy-futures", - "embassy-nrf", - "embassy-sync", - "embassy-time", - "embedded-hal 1.0.0", - "embedded-io", - "embedded-storage", - "futures", - "heapless 0.7.17", - "static_cell", - "watchful-infinitime-recovery", -] diff --git a/infinitime-recovery/app/Cargo.toml b/infinitime-recovery/app/Cargo.toml index e1cec12..4f707f7 100644 --- a/infinitime-recovery/app/Cargo.toml +++ b/infinitime-recovery/app/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "watchful-infinitime-recovery-app" +name = "recovery-app" version = "0.1.0" license = "MIT OR Apache-2.0" build = "build.rs" diff --git a/infinitime-recovery/app/memory.x b/infinitime-recovery/app/memory.x index d57d1a9..d741b7f 100644 --- a/infinitime-recovery/app/memory.x +++ b/infinitime-recovery/app/memory.x @@ -1,6 +1,6 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - FLASH : ORIGIN = 0x00039000, LENGTH = 324K - RAM : ORIGIN = 0x20000008, LENGTH = 32760 + FLASH : ORIGIN = 0x00039000, LENGTH = 284K + RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32760 } diff --git a/infinitime-recovery/app/src/main.rs b/infinitime-recovery/app/src/main.rs index db5ebdd..1cbf510 100644 --- a/infinitime-recovery/app/src/main.rs +++ b/infinitime-recovery/app/src/main.rs @@ -4,10 +4,11 @@ #![feature(impl_trait_in_assoc_type)] use embassy_executor::{InterruptExecutor, Spawner}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::interrupt; use embassy_nrf::interrupt::{InterruptExt, Priority}; use embassy_nrf::nvmc::Nvmc; -use embassy_time::{Duration, Timer}; +use embassy_time::{Duration, Instant, Timer}; #[interrupt] unsafe fn SWI0_EGU0() { @@ -23,8 +24,9 @@ static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); struct AlignedBuffer([u8; 4096]); #[embassy_executor::main] -async fn main(_s: Spawner) { +async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_17, Level::Low, OutputDrive::Standard); // Medium-priority executor: SWI0_EGU0, priority level 7 interrupt::SWI0_EGU0.set_priority(Priority::P6); @@ -35,15 +37,21 @@ async fn main(_s: Spawner) { let mut buf = AlignedBuffer([0; 4096]); let mut internal_flash = Nvmc::new(p.NVMC); - watchful_infinitime_recovery::recover( - &mut internal_flash, - &mut embassy_time::Delay, - &mut buf.0, - MCUBOOT, - RECOVERY, - ) - .await; - Timer::after(Duration::from_secs(5)).await; + // watchful_infinitime_recovery::recover( + // &mut internal_flash, + // &mut embassy_time::Delay, + // &mut buf.0, + // MCUBOOT, + // RECOVERY, + // ) + // .await; + let timeout = Instant::now() + Duration::from_secs(60); + while Instant::now() < timeout { + led.set_low(); + Timer::after(Duration::from_millis(400)).await; + led.set_high(); + Timer::after(Duration::from_millis(400)).await; + } cortex_m::peripheral::SCB::sys_reset(); } diff --git a/infinitime-recovery/boot/Cargo.toml b/infinitime-recovery/boot/Cargo.toml index 33d7967..5c3dfb3 100644 --- a/infinitime-recovery/boot/Cargo.toml +++ b/infinitime-recovery/boot/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "reloader-bootloader" +name = "recovery-boot" version = "0.1.0" license = "MIT OR Apache-2.0" resolver = "2" diff --git a/infinitime-recovery/boot/memory.x b/infinitime-recovery/boot/memory.x index 7c11a8d..9ba2765 100644 --- a/infinitime-recovery/boot/memory.x +++ b/infinitime-recovery/boot/memory.x @@ -4,7 +4,7 @@ MEMORY FLASH : ORIGIN = 0x00026000, LENGTH = 16K RELOADER : ORIGIN = 0x00039000, LENGTH = 284K - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 0xfff8 } __reloader_start = ORIGIN(RELOADER); diff --git a/infinitime-recovery/boot/src/main.rs b/infinitime-recovery/boot/src/main.rs index 1649d51..cf50eeb 100644 --- a/infinitime-recovery/boot/src/main.rs +++ b/infinitime-recovery/boot/src/main.rs @@ -3,6 +3,7 @@ use cortex_m_rt::{entry, exception}; use embassy_nrf as _; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; #[entry] fn main() -> ! { @@ -11,7 +12,6 @@ fn main() -> ! { static __reloader_start: u32; } let start = &__reloader_start as *const u32 as u32; - let mut p = cortex_m::Peripherals::steal(); p.SCB.invalidate_icache(); p.SCB.vtor.write(start); diff --git a/scripts/flash_infinitime.sh b/scripts/flash_infinitime.sh index 78bcf55..832f800 100755 --- a/scripts/flash_infinitime.sh +++ b/scripts/flash_infinitime.sh @@ -1,4 +1,4 @@ probe-rs erase --chip nRF52832_xxAA #probe-rs download pinetime-mcuboot-app-image-1.13.0.bin --format Binary --base-address 0x8000 --chip nRF52832_xxAA -probe-rs download pinetime-mcuboot-app-image-1.11.0.bin --format Binary --base-address 0x8000 --chip nRF52832_xxAA -probe-rs download mcuboot.bin --format Binary --chip nRF52832_xxAA +probe-rs download pinetime-mcuboot-app-image-1.15.0.bin --binary-format Binary --base-address 0x8000 --chip nRF52832_xxAA +probe-rs download mcuboot.bin --binary-format Binary --chip nRF52832_xxAA diff --git a/scripts/prepare.sh b/scripts/prepare.sh index fb27ae9..3e7ea76 100755 --- a/scripts/prepare.sh +++ b/scripts/prepare.sh @@ -4,5 +4,5 @@ pushd reloader/boot && cargo objcopy --release -- -O ihex ../reloader-boot.hex & pushd reloader/app && cargo objcopy --release -- -O ihex ../reloader-app.hex && popd mergehex -m reloader/reloader-boot.hex reloader/reloader-app.hex -o reloader.bin -imgtool create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header reloader.bin watchful-reloader-image.bin -adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application watchful-reloader-image.bin watchful-reloader-dfu.zip +#imgtool create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header reloader.bin watchful-reloader-image.bin +#adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application watchful-reloader-image.bin watchful-reloader-dfu.zip diff --git a/scripts/prepare_recovery.sh b/scripts/prepare_recovery.sh index 56a92f8..6184d81 100755 --- a/scripts/prepare_recovery.sh +++ b/scripts/prepare_recovery.sh @@ -1,12 +1,18 @@ #!/usr/bin/env sh +set -e -pushd infinitime-recovery/boot && cargo objcopy --release -- -O ihex ../../boot-recovery.hex && popd -pushd infinitime-recovery/app && cargo objcopy --release -- -O ihex ../../app-recovery.hex && popd +pushd infinitime-recovery/boot && cargo clean && cargo objcopy --release && cp target/thumbv7em-none-eabi/release/recovery-boot ../../boot-recovery.elf && popd +pushd infinitime-recovery/app && cargo clean && cargo objcopy --release && cp target/thumbv7em-none-eabi/release/recovery-app ../../app-recovery.elf && popd -mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin +#mergehex -m boot-recovery.elf app-recovery.elf -o infinitime-recovery.elf +#mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin +mergehex -m boot-recovery.elf app-recovery.elf -o infinitime-recovery.elf +arm-none-eabi-objcopy -I elf32-littlearm infinitime-recovery.elf -O binary infinitime-recovery.bin tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header infinitime-recovery.bin infinitime-recovery-image.bin +adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application infinitime-recovery-image.bin infinitime-recovery-dfu.zip + #probe-rs erase --chip nRF52832_xxAA #probe-rs download blinky-image.bin --base-address 0x8000 --binary-format Binary --chip nRF52832_xxAA #probe-rs download bootloader-1.0.1.bin --base-address 0 --binary-format Binary --chip nRF52832_xxAA From 73f7588906d5cd549f1b73390459e95b922dac89 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 11 Dec 2024 23:06:07 +0100 Subject: [PATCH 14/21] Working on time sync --- README.md | 5 ++- firmware/.cargo/config.toml | 4 +-- firmware/build.rs | 11 +++++-- firmware/memory-bm.x | 6 ++++ firmware/memory-img.x | 6 ++++ firmware/memory.x | 7 ----- firmware/src/ble.rs | 62 +++++++++++++++++++++++++++++++++---- firmware/src/main.rs | 2 +- 8 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 firmware/memory-bm.x create mode 100644 firmware/memory-img.x delete mode 100644 firmware/memory.x diff --git a/README.md b/README.md index 38231d9..6654fea 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,14 @@ Firmware for Pinetime based on [Embassy](https://embassy.dev). The goal is to pr ## Features * Basic UI with menus using [`embedded-graphics`](https://crates.io/crates/embedded-graphics). -* Implements Nordic DFU protocol so you can update from a phone app such as nRF Connect to perform firmware updates. * Automatically synchronizes time with using BLE standard Current Time Service. * Rollback to previous firmware if reset or crashing before new firmware is validated in watch UI. * Compatible with existing InfiniTime bootloader. +Some features that has been removed after recent switch to mcuboot, but will be added again soon: + +* Implements Nordic DFU protocol so you can update from a phone app such as nRF Connect to perform firmware updates. + ## Getting started If you have InfiniTime running already, it's easy to try out Watchful. You can use the same app you use to update InfiniTime to try out Watchful (such as GadgetBridge). diff --git a/firmware/.cargo/config.toml b/firmware/.cargo/config.toml index ddd65a1..1cc6621 100644 --- a/firmware/.cargo/config.toml +++ b/firmware/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] +#build-std = ["core"] +#build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace nRF82832_xxAA with your chip as listed in `probe-rs-cli chip list` diff --git a/firmware/build.rs b/firmware/build.rs index ded35b2..ec752eb 100644 --- a/firmware/build.rs +++ b/firmware/build.rs @@ -19,7 +19,14 @@ fn linker_data() -> &'static [u8] { #[cfg(feature = "baremetal")] return include_bytes!("memory-bm.x"); #[cfg(not(feature = "baremetal"))] - return include_bytes!("memory.x"); + return include_bytes!("memory-img.x"); +} + +fn linker_file() -> &'static str { + #[cfg(feature = "baremetal")] + return "memory-bm.x"; + #[cfg(not(feature = "baremetal"))] + return "memory-img.x"; } fn main() { @@ -37,7 +44,7 @@ fn main() { // any file in the project changes. By specifying `memory.x` // here, we ensure the build script is only re-run when // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rerun-if-changed={}", linker_file()); println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); diff --git a/firmware/memory-bm.x b/firmware/memory-bm.x new file mode 100644 index 0000000..aa6d7ee --- /dev/null +++ b/firmware/memory-bm.x @@ -0,0 +1,6 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 32768 +} diff --git a/firmware/memory-img.x b/firmware/memory-img.x new file mode 100644 index 0000000..aa6d7ee --- /dev/null +++ b/firmware/memory-img.x @@ -0,0 +1,6 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 32768 +} diff --git a/firmware/memory.x b/firmware/memory.x deleted file mode 100644 index edecee9..0000000 --- a/firmware/memory.x +++ /dev/null @@ -1,7 +0,0 @@ -MEMORY -{ - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - FLASH : ORIGIN = 0x00008020, LENGTH = 256K - /*FLASH : ORIGIN = 0x00000000, LENGTH = 256K */ - RAM : ORIGIN = 0x20000008, LENGTH = 32760 -} diff --git a/firmware/src/ble.rs b/firmware/src/ble.rs index 818b4d9..6b01b7f 100644 --- a/firmware/src/ble.rs +++ b/firmware/src/ble.rs @@ -63,7 +63,6 @@ struct CurrentTimeServiceClient { #[characteristic(uuid = "2a2b", write, read, notify)] current_time: Vec, } - pub async fn sync_time(conn: &Connection, clock: &crate::clock::Clock) { if let Ok(time_client) = gatt_client::discover::(&conn).await { info!("Found time server on peer, synchronizing time"); @@ -184,7 +183,7 @@ pub fn start(spawner: Spawner, controller: NrfController, dfu_config: DfuConfig< spawner.must_spawn(ble_task(runner)); spawner.must_spawn(gatt_task(server)); - spawner.must_spawn(advertise_task(peripheral, server, dfu_config)); + spawner.must_spawn(advertise_task(stack, peripheral, server, dfu_config)); } #[embassy_executor::task] @@ -199,6 +198,7 @@ async fn gatt_task(server: &'static PineTimeServer<'_, '_, NrfController>) { #[embassy_executor::task] async fn advertise_task( + stack: Stack<'static, NrfController>, mut peripheral: Peripheral<'static, NrfController>, server: &'static PineTimeServer<'_, '_, NrfController>, mut dfu_config: DfuConfig<'static>, @@ -225,7 +225,7 @@ async fn advertise_task( ); loop { match advertiser.accept().await { - Ok(conn) => process(conn, server, &mut dfu_config).await, + Ok(conn) => process(stack, conn, server, &mut dfu_config).await, Err(e) => { warn!("Error advertising: {:?}", e); } @@ -234,6 +234,7 @@ async fn advertise_task( } async fn process( + stack: Stack<'static, NrfController>, connection: Connection<'static>, server: &'static PineTimeServer<'_, '_, NrfController>, dfu_config: &mut DfuConfig<'static>, @@ -257,8 +258,12 @@ async fn process( len: 0, }; - let mut dfu = dfu_config.dfu(); - let mut target = DfuTarget::new(dfu.size(), fw_info, hw_info); + // Synchronize time + let s = Spawner::for_current_executor().await; + s.must_spawn(sync_time(stack, connection.clone())); + + //let mut dfu = dfu_config.dfu(); + //let mut target = DfuTarget::new(dfu.size(), fw_info, hw_info); loop { match connection.next().await { @@ -267,6 +272,8 @@ async fn process( } ConnectionEvent::Gatt { event, connection } => match event { GattEvent::Write { value_handle } => { + defmt::info!("Gatt write!"); + /* if let Some(DfuStatus::DoneReset) = server.handle(&mut target, &mut dfu, connection, value_handle).await { @@ -282,10 +289,53 @@ async fn process( // panic!("Error marking firmware updated: {:?}", e); // } //} - } + }*/ } _ => {} }, } } } + +#[embassy_executor::task] +async fn sync_time(stack: Stack<'static, NrfController>, conn: Connection<'static>) { + info!("Synchronizing time, creating gatt client"); + let client = unwrap!(GattClient::<_, 10, 24>::new(stack, &conn).await); + + info!("Discovering time service"); + let services = unwrap!(client.services_by_uuid(&Uuid::new_short(0x1805)).await); + let service = services.first().unwrap().clone(); + + info!("Looking for value handle"); + let c: Characteristic = unwrap!(client.characteristic_by_uuid(&service, &Uuid::new_short(0x2a2b)).await); + + info!("Reading characteristic"); + let mut data = [0; 10]; + unwrap!(client.read_characteristic(&c, &mut data[..]).await); + + if let Some(time) = parse_time(data) { + crate::CLOCK.set(time); + } +} + +fn parse_time(data: [u8; 10]) -> Option { + let year = u16::from_le_bytes([data[0], data[1]]); + let month = data[2]; + let day = data[3]; + let hour = data[4]; + let minute = data[5]; + let second = data[6]; + let _weekday = data[7]; + let secs_frac = data[8]; + + if let Ok(month) = month.try_into() { + let date = time::Date::from_calendar_date(year as i32, month, day); + let micros = secs_frac as u32 * 1000000 / 256; + let time = time::Time::from_hms_micro(hour, minute, second, micros); + if let (Ok(time), Ok(date)) = (time, date) { + let dt = time::PrimitiveDateTime::new(date, time); + return Some(dt); + } + } + None +} diff --git a/firmware/src/main.rs b/firmware/src/main.rs index bfadccc..61d3ae2 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -185,7 +185,7 @@ async fn main(s: Spawner) { let dfu_config = DfuConfig::new(internal_flash, external_flash); // BLE - // ble::start(s, sdc, dfu_config); + ble::start(s, sdc, dfu_config); // Display From 4178a532cb9e01fc0da3c7f49da24ea535e864ec Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:17:43 +0100 Subject: [PATCH 15/21] FIx recovery --- scripts/flashsd.sh | 4 ++-- scripts/prepare_recovery.sh | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/flashsd.sh b/scripts/flashsd.sh index b91c5ce..2b7d1e6 100755 --- a/scripts/flashsd.sh +++ b/scripts/flashsd.sh @@ -1,2 +1,2 @@ -probe-rs-cli erase --chip nRF52832_xxAA -probe-rs-cli download softdevice/s132_nrf52_7.3.0_softdevice.hex --chip nRF52832_xxAA --format Hex +probe-rs erase --chip nRF52832_xxAA +probe-rs download s132_nrf52_7.3.0_softdevice.hex --chip nRF52832_xxAA --binary-format Hex diff --git a/scripts/prepare_recovery.sh b/scripts/prepare_recovery.sh index 6184d81..feaa4ef 100755 --- a/scripts/prepare_recovery.sh +++ b/scripts/prepare_recovery.sh @@ -6,12 +6,15 @@ pushd infinitime-recovery/app && cargo clean && cargo objcopy --release && cp ta #mergehex -m boot-recovery.elf app-recovery.elf -o infinitime-recovery.elf #mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.bin -mergehex -m boot-recovery.elf app-recovery.elf -o infinitime-recovery.elf -arm-none-eabi-objcopy -I elf32-littlearm infinitime-recovery.elf -O binary infinitime-recovery.bin +arm-none-eabi-objcopy -I elf32-littlearm boot-recovery.elf -O ihex boot-recovery.hex +arm-none-eabi-objcopy -I elf32-littlearm app-recovery.elf -O ihex app-recovery.hex -tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header infinitime-recovery.bin infinitime-recovery-image.bin +mergehex -m boot-recovery.hex app-recovery.hex -o infinitime-recovery.hex +arm-none-eabi-objcopy -I ihex infinitime-recovery.hex -O binary infinitime-recovery.bin -adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application infinitime-recovery-image.bin infinitime-recovery-dfu.zip +# tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header infinitime-recovery.bin infinitime-recovery-image.bin +# +adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application infinitime-recovery.bin infinitime-recovery-dfu.zip #probe-rs erase --chip nRF52832_xxAA #probe-rs download blinky-image.bin --base-address 0x8000 --binary-format Binary --chip nRF52832_xxAA From 5991e7fa46dcbe3a1eec25abbe4b2aa3a0cca79d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:20:26 +0100 Subject: [PATCH 16/21] Fix time sync --- firmware/Cargo.lock | 19 ++++-------- firmware/Cargo.toml | 2 +- firmware/src/ble.rs | 76 ++++++++++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 993f919..e8ad3f8 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -387,9 +387,8 @@ dependencies = [ [[package]] name = "embassy-executor" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ed0e24bdd4a5f4ff1b72ee4f264b1d23e179ea71a77d984b5fd24877a2bbe1" +version = "0.6.3" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "cortex-m 0.7.7", "critical-section", @@ -402,9 +401,8 @@ dependencies = [ [[package]] name = "embassy-executor-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d4c0c34b32c2c653c9eecce1cefaf8539dd9a54e61deb5499254f01e2fcac2" +version = "0.6.2" +source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" dependencies = [ "darling", "proc-macro2", @@ -1470,7 +1468,7 @@ dependencies = [ [[package]] name = "trouble-host" version = "0.1.0" -source = "git+https://github.com/embassy-rs/trouble.git?rev=b470edeff6eeb76655ee69d503f3776a166a7375#b470edeff6eeb76655ee69d503f3776a166a7375" +source = "git+https://github.com/embassy-rs/trouble.git?rev=aa9a17f4aef51e67744fa922ba8c02c4bbf13fc2#aa9a17f4aef51e67744fa922ba8c02c4bbf13fc2" dependencies = [ "bt-hci", "defmt", @@ -1490,7 +1488,7 @@ dependencies = [ [[package]] name = "trouble-host-macros" version = "0.1.0" -source = "git+https://github.com/embassy-rs/trouble.git?rev=b470edeff6eeb76655ee69d503f3776a166a7375#b470edeff6eeb76655ee69d503f3776a166a7375" +source = "git+https://github.com/embassy-rs/trouble.git?rev=aa9a17f4aef51e67744fa922ba8c02c4bbf13fc2#aa9a17f4aef51e67744fa922ba8c02c4bbf13fc2" dependencies = [ "Inflector", "darling", @@ -1695,8 +1693,3 @@ checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] - -[[patch.unused]] -name = "embassy-executor" -version = "0.6.3" -source = "git+https://github.com/embassy-rs/embassy.git?rev=fe79af56141adfeacb3cfcefc4400da0c5aabb5f#fe79af56141adfeacb3cfcefc4400da0c5aabb5f" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 8d1967b..f4c2e94 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -56,7 +56,7 @@ vergen = { version = "8", features = ["build", "git", "gitcl"] } hrs3300 = { git = "https://github.com/lulf/hrs3300-rs.git", branch = "hal-1.0" } nrf-mpsl = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "9696ce04fd417dc5c448edbafab3fef23f2f34cd" } nrf-sdc = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "9696ce04fd417dc5c448edbafab3fef23f2f34cd" } -trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "b470edeff6eeb76655ee69d503f3776a166a7375"} +trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "aa9a17f4aef51e67744fa922ba8c02c4bbf13fc2"} embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", rev = "fe79af56141adfeacb3cfcefc4400da0c5aabb5f" } diff --git a/firmware/src/ble.rs b/firmware/src/ble.rs index 6b01b7f..2be6338 100644 --- a/firmware/src/ble.rs +++ b/firmware/src/ble.rs @@ -1,5 +1,6 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; use embedded_storage::nor_flash::NorFlash; use heapless::Vec; use nrf_dfu_target::prelude::{DfuRequest, DfuStatus, DfuTarget, FirmwareInfo, FirmwareType, HardwareInfo}; @@ -54,7 +55,7 @@ pub struct NrfDfuService { #[gatt_server] pub struct PineTimeServer { dfu: NrfDfuService, - // uart: NrfUartService, + uart: NrfUartService, } /* @@ -175,7 +176,7 @@ pub fn start(spawner: Spawner, controller: NrfController, dfu_config: DfuConfig< stack, GapConfig::Peripheral(PeripheralConfig { name: "Watchful", - appearance: &appearance::power_device::GENERIC_POWER_DEVICE, + appearance: &appearance::watch::SMARTWATCH, }), )); static SERVER: StaticCell> = StaticCell::new(); @@ -192,7 +193,7 @@ async fn ble_task(mut runner: Runner<'static, NrfController>) { } #[embassy_executor::task] -async fn gatt_task(server: &'static PineTimeServer<'_, '_, NrfController>) { +async fn gatt_task(server: &'static PineTimeServer<'static, 'static, NrfController>) { unwrap!(server.run().await); } @@ -200,7 +201,7 @@ async fn gatt_task(server: &'static PineTimeServer<'_, '_, NrfController>) { async fn advertise_task( stack: Stack<'static, NrfController>, mut peripheral: Peripheral<'static, NrfController>, - server: &'static PineTimeServer<'_, '_, NrfController>, + server: &'static PineTimeServer<'static, 'static, NrfController>, mut dfu_config: DfuConfig<'static>, ) { let mut advertiser_data = [0; 31]; @@ -212,18 +213,18 @@ async fn advertise_task( ], &mut advertiser_data[..], )); - let mut advertiser = unwrap!( - peripheral - .advertise( - &Default::default(), - Advertisement::ConnectableScannableUndirected { - adv_data: &advertiser_data[..], - scan_data: &[], - }, - ) - .await - ); loop { + let advertiser = unwrap!( + peripheral + .advertise( + &Default::default(), + Advertisement::ConnectableScannableUndirected { + adv_data: &advertiser_data[..], + scan_data: &[], + }, + ) + .await + ); match advertiser.accept().await { Ok(conn) => process(stack, conn, server, &mut dfu_config).await, Err(e) => { @@ -267,12 +268,12 @@ async fn process( loop { match connection.next().await { - ConnectionEvent::Disconnected { reason: _ } => { + ConnectionEvent::Disconnected { reason } => { + defmt::info!("[ble] disconnected: {:?}", reason); break; } ConnectionEvent::Gatt { event, connection } => match event { GattEvent::Write { value_handle } => { - defmt::info!("Gatt write!"); /* if let Some(DfuStatus::DoneReset) = server.handle(&mut target, &mut dfu, connection, value_handle).await @@ -299,22 +300,33 @@ async fn process( #[embassy_executor::task] async fn sync_time(stack: Stack<'static, NrfController>, conn: Connection<'static>) { - info!("Synchronizing time, creating gatt client"); + info!("[ble] synchronizing time"); let client = unwrap!(GattClient::<_, 10, 24>::new(stack, &conn).await); - - info!("Discovering time service"); - let services = unwrap!(client.services_by_uuid(&Uuid::new_short(0x1805)).await); - let service = services.first().unwrap().clone(); - - info!("Looking for value handle"); - let c: Characteristic = unwrap!(client.characteristic_by_uuid(&service, &Uuid::new_short(0x2a2b)).await); - - info!("Reading characteristic"); - let mut data = [0; 10]; - unwrap!(client.read_characteristic(&c, &mut data[..]).await); - - if let Some(time) = parse_time(data) { - crate::CLOCK.set(time); + match select(client.task(), async { + let services = client.services_by_uuid(&Uuid::new_short(0x1805)).await?; + if let Some(service) = services.first() { + let c: Characteristic = client + .characteristic_by_uuid(&service, &Uuid::new_short(0x2a2b)) + .await?; + + let mut data = [0; 10]; + client.read_characteristic(&c, &mut data[..]).await?; + + if let Some(time) = parse_time(data) { + crate::CLOCK.set(time); + } + } + Ok::<(), BleHostError>(()) + }) + .await + { + Either::First(_) => panic!("[ble] gatt client exited prematurely"), + Either::Second(Ok(_)) => { + info!("[ble] time sync completed"); + } + Either::Second(Err(e)) => { + warn!("[ble] time sync error: {:?}", e); + } } } From 561307977a9d5c25212a56a445ba857ba17cc5f2 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:20:37 +0100 Subject: [PATCH 17/21] Working infinitime recovery --- infinitime-recovery/app/memory.x | 7 ++++++- infinitime-recovery/app/src/main.rs | 22 ++++++++++++---------- infinitime-recovery/boot/Cargo.toml | 3 +++ infinitime-recovery/boot/build.rs | 1 + infinitime-recovery/boot/src/main.rs | 11 +++++------ 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/infinitime-recovery/app/memory.x b/infinitime-recovery/app/memory.x index d741b7f..9860abe 100644 --- a/infinitime-recovery/app/memory.x +++ b/infinitime-recovery/app/memory.x @@ -1,6 +1,11 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ + MBR : ORIGIN = 0x00000000, LENGTH = 4K + SOFTDEVICE : ORIGIN = 0x00001000, LENGTH = 148K FLASH : ORIGIN = 0x00039000, LENGTH = 284K - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32760 + BOOTLOADER : ORIGIN = 0x00077000, LENGTH = 32K + BOOTLOADER_STATE : ORIGIN = 0x0007F000, LENGTH = 4K + + RAM : ORIGIN = 0x2000BAF0, LENGTH = 17680 } diff --git a/infinitime-recovery/app/src/main.rs b/infinitime-recovery/app/src/main.rs index 1cbf510..6650eac 100644 --- a/infinitime-recovery/app/src/main.rs +++ b/infinitime-recovery/app/src/main.rs @@ -26,7 +26,7 @@ struct AlignedBuffer([u8; 4096]); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut led = Output::new(p.P0_17, Level::Low, OutputDrive::Standard); + let mut led = Output::new(p.P0_22, Level::Low, OutputDrive::Standard); // Medium-priority executor: SWI0_EGU0, priority level 7 interrupt::SWI0_EGU0.set_priority(Priority::P6); @@ -37,21 +37,23 @@ async fn main(_spawner: Spawner) { let mut buf = AlignedBuffer([0; 4096]); let mut internal_flash = Nvmc::new(p.NVMC); - // watchful_infinitime_recovery::recover( - // &mut internal_flash, - // &mut embassy_time::Delay, - // &mut buf.0, - // MCUBOOT, - // RECOVERY, - // ) - // .await; - let timeout = Instant::now() + Duration::from_secs(60); + watchful_infinitime_recovery::recover( + &mut internal_flash, + &mut embassy_time::Delay, + &mut buf.0, + MCUBOOT, + RECOVERY, + ) + .await; + + let timeout = Instant::now() + Duration::from_secs(10); while Instant::now() < timeout { led.set_low(); Timer::after(Duration::from_millis(400)).await; led.set_high(); Timer::after(Duration::from_millis(400)).await; } + cortex_m::peripheral::SCB::sys_reset(); } diff --git a/infinitime-recovery/boot/Cargo.toml b/infinitime-recovery/boot/Cargo.toml index 5c3dfb3..2935909 100644 --- a/infinitime-recovery/boot/Cargo.toml +++ b/infinitime-recovery/boot/Cargo.toml @@ -11,6 +11,9 @@ embassy-nrf = { version = "0.1.0", default-features = false, features = ["rt", " static_cell = "1.1" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.3" +defmt = "0.3" +panic-probe = { version = "0.3", features = ["print-defmt"] } +defmt-rtt = "0.4" [profile.release] debug = 2 diff --git a/infinitime-recovery/boot/build.rs b/infinitime-recovery/boot/build.rs index cd1a264..30691aa 100644 --- a/infinitime-recovery/boot/build.rs +++ b/infinitime-recovery/boot/build.rs @@ -31,4 +31,5 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); } diff --git a/infinitime-recovery/boot/src/main.rs b/infinitime-recovery/boot/src/main.rs index cf50eeb..5b29d40 100644 --- a/infinitime-recovery/boot/src/main.rs +++ b/infinitime-recovery/boot/src/main.rs @@ -2,16 +2,20 @@ #![no_main] use cortex_m_rt::{entry, exception}; -use embassy_nrf as _; use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; #[entry] fn main() -> ! { + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_22, Level::Low, OutputDrive::Standard); + led.set_low(); unsafe { extern "C" { static __reloader_start: u32; } let start = &__reloader_start as *const u32 as u32; + defmt::info!("Loading at {:08x}", start); let mut p = cortex_m::Peripherals::steal(); p.SCB.invalidate_icache(); p.SCB.vtor.write(start); @@ -33,8 +37,3 @@ unsafe fn DefaultHandler(_: i16) -> ! { panic!("DefaultHandler #{:?}", irqn); } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - cortex_m::asm::udf(); -} From 8e2ec8952460e1b97d513aeeb13b83dbf4d261e8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:20:50 +0100 Subject: [PATCH 18/21] Remove old reloader --- reloader/.cargo/config.toml | 21 - reloader/Cargo.lock | 1017 ----------------------------------- reloader/Cargo.toml | 33 -- reloader/app/Cargo.toml | 30 -- reloader/app/build.rs | 39 -- reloader/app/memory.x | 21 - reloader/app/src/main.rs | 152 ------ reloader/boot/Cargo.toml | 12 - reloader/boot/build.rs | 34 -- reloader/boot/memory.x | 11 - reloader/boot/src/main.rs | 41 -- 11 files changed, 1411 deletions(-) delete mode 100644 reloader/.cargo/config.toml delete mode 100644 reloader/Cargo.lock delete mode 100644 reloader/Cargo.toml delete mode 100644 reloader/app/Cargo.toml delete mode 100644 reloader/app/build.rs delete mode 100644 reloader/app/memory.x delete mode 100644 reloader/app/src/main.rs delete mode 100644 reloader/boot/Cargo.toml delete mode 100644 reloader/boot/build.rs delete mode 100644 reloader/boot/memory.x delete mode 100644 reloader/boot/src/main.rs diff --git a/reloader/.cargo/config.toml b/reloader/.cargo/config.toml deleted file mode 100644 index 85c2cad..0000000 --- a/reloader/.cargo/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -[unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] - -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82832_xxAA with your chip as listed in `probe-rs-cli chip list` -#runner = "probe-rs-cli run --no-location --chip nRF52832_xxAA" -runner = "probe-run --chip nRF52832_xxAA" -rustflags = [ -# "-Z", "features=host_dep", - # Code-size optimizations. - "-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", # try different values here - "-C", "no-vectorize-loops", # try with and without this -] - -[build] -target = "thumbv7em-none-eabi" - -[env] -DEFMT_LOG = "info" diff --git a/reloader/Cargo.lock b/reloader/Cargo.lock deleted file mode 100644 index 9ddfbd0..0000000 --- a/reloader/Cargo.lock +++ /dev/null @@ -1,1017 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "atomic-polyfill" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" -dependencies = [ - "critical-section", -] - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "az" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version 0.2.3", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bytemuck" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal", - "bitfield", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "darling" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.29", -] - -[[package]] -name = "darling_macro" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "defmt" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" -dependencies = [ - "bitflags 1.3.2", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" -dependencies = [ - "defmt-parser", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "defmt-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609923761264dd99ed9c7d209718cda4631c5fe84668e0f0960124cbb844c49f" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "embassy-boot" -version = "0.1.1" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "digest", - "embassy-embedded-hal", - "embassy-sync", - "embedded-storage", - "embedded-storage-async", - "signature", -] - -[[package]] -name = "embassy-boot-nrf" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "cfg-if", - "cortex-m", - "cortex-m-rt", - "embassy-boot", - "embassy-nrf", - "embassy-sync", - "embedded-storage", - "embedded-storage-async", -] - -[[package]] -name = "embassy-embedded-hal" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "defmt", - "embassy-futures", - "embassy-sync", - "embassy-time", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0-rc.1", - "embedded-hal-async", - "embedded-storage", - "embedded-storage-async", - "nb 1.1.0", -] - -[[package]] -name = "embassy-executor" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1791d46f93d9b90bd557c09bbe8408a578bdcde240889bc773f1788c5c828b" -dependencies = [ - "atomic-polyfill 1.0.3", - "cortex-m", - "critical-section", - "defmt", - "embassy-macros", - "embassy-time", - "futures-util", - "static_cell", -] - -[[package]] -name = "embassy-futures" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" - -[[package]] -name = "embassy-hal-internal" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "cortex-m", - "critical-section", - "defmt", - "num-traits", -] - -[[package]] -name = "embassy-macros" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d3eef431adfc517df1601e367f72b1c28a51c6eb91def7dc297be7fc8789a4" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "embassy-nrf" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "cfg-if", - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "embassy-embedded-hal", - "embassy-hal-internal", - "embassy-sync", - "embassy-time", - "embassy-usb-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0-rc.1", - "embedded-hal-async", - "embedded-io 0.5.0", - "embedded-io-async", - "embedded-storage", - "embedded-storage-async", - "fixed", - "futures", - "nrf52805-pac", - "nrf52810-pac", - "nrf52811-pac", - "nrf52820-pac", - "nrf52832-pac", - "nrf52833-pac", - "nrf52840-pac", - "nrf5340-app-pac", - "nrf5340-net-pac", - "nrf9160-pac", - "rand_core", -] - -[[package]] -name = "embassy-sync" -version = "0.2.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "cfg-if", - "critical-section", - "defmt", - "futures-util", - "heapless", -] - -[[package]] -name = "embassy-time" -version = "0.1.3" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "atomic-polyfill 1.0.3", - "cfg-if", - "critical-section", - "defmt", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0-rc.1", - "futures-util", - "heapless", -] - -[[package]] -name = "embassy-usb-driver" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" -dependencies = [ - "defmt", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2894bc2f0457b8ca3d6b8ab8aad64d9337583672494013457f86c5a9146c0e22" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a8a3517745342155b3b00895a0f78417a453fb800d97a8bf4777d5720acde9" -dependencies = [ - "embedded-hal 1.0.0-rc.1", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bbadc628dc286b9ae02f0cb0f5411c056eb7487b72f0083203f115de94060" - -[[package]] -name = "embedded-io-async" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1394754ad749a560b25a0c70dcd2b66a450824a1311fc475bb2ccbfabe7f8414" -dependencies = [ - "embedded-io 0.5.0", -] - -[[package]] -name = "embedded-storage" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723" - -[[package]] -name = "embedded-storage-async" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052997a894670d0cde873faa7405bc98e2fd29f569d2acd568561bc1c396b35a" -dependencies = [ - "embedded-storage", -] - -[[package]] -name = "fixed" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9" -dependencies = [ - "az", - "bytemuck", - "half", - "typenum", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-macro", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "half" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "heapless" -version = "0.7.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" -dependencies = [ - "atomic-polyfill 0.1.11", - "hash32", - "rustc_version 0.4.0", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nrf52805-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2da657648039d59f4de6bc31b948dd3a5d03b32529a4d5d19d9e2dd9d4bfa6c" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52810-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26b12d5af17a9f4bb9a06ca9a1f814bca3d67bc8715b23f8dc230b09a227666" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52811-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4179b2a7ed0b2fd5e109d0fab9b4fc55b3936b2a4916a9306d22e5bc8dc1fd8f" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52820-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4791cff995e6419a5ad1aebc3b3c9539d79125ca85eb5bfd2cff9b470b81071" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52832-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0242b685c9c15648fb803e155628f42ace457478b2cb930868f40cae2db925e0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52833-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10e1358255b360cdc816dd7b6ef81be8c8499c0998277e5249bed222bd0f5241" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf52840-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf5340-app-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c88824573cd150fe9f27c1a48cea31a8cb24d3322df488875775143618c087a" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf5340-net-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c03e44df22fe5888109fe42e523162c7059adf4d30860f4f73ecc8b1fc16fe" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "nrf9160-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7344d74afb5684e00c48d175cad9619f36d629cfb0687d33b4d1bb86fba688f4" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "panic-probe" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9" -dependencies = [ - "cortex-m", - "defmt", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pinetime-flash" -version = "0.1.0" -dependencies = [ - "bitflags 2.4.0", - "defmt", - "embedded-hal 1.0.0-rc.1", - "embedded-storage", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "reloader-bootloader" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "embassy-nrf", - "static_cell", -] - -[[package]] -name = "reloader-embassy" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "defmt", - "defmt-rtt", - "embassy-boot", - "embassy-boot-nrf", - "embassy-embedded-hal", - "embassy-executor", - "embassy-futures", - "embassy-nrf", - "embassy-sync", - "embassy-time", - "embedded-hal 1.0.0-rc.1", - "embedded-io 0.4.0", - "embedded-storage", - "futures", - "heapless", - "panic-probe", - "pinetime-flash", - "static_cell", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.18", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_cell" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cd323fc21eb534f903ee78d781d622099f9716c5b408ed23bcf39f8f1651c0" -dependencies = [ - "atomic-polyfill 1.0.3", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" -dependencies = [ - "vcell", -] - -[[patch.unused]] -name = "embassy-executor" -version = "0.3.0" -source = "git+https://github.com/embassy-rs/embassy.git?branch=main#a36ee75d196752abc798d9eaf9ddedd5f15ec97a" diff --git a/reloader/Cargo.toml b/reloader/Cargo.toml deleted file mode 100644 index 5aca369..0000000 --- a/reloader/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[workspace] -members = [ - "app", - "boot" -] - -resolver = "2" - -[patch.crates-io] -# embassy-executor = { path = "../../embassy/embassy-executor" } -# embassy-time = {path = "../../embassy/embassy-time"} -# embassy-sync = {path = "../../embassy/embassy-sync"} -# embassy-nrf = {path = "../../embassy/embassy-nrf"} -# embassy-embedded-hal = {path = "../../embassy/embassy-embedded-hal"} -# embassy-boot = {path = "../../embassy/embassy-boot/boot"} -# embassy-boot-nrf = {path = "../../embassy/embassy-boot/nrf"} -# embassy-futures = {path = "../../embassy/embassy-futures"} -embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-boot = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-boot-nrf = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } -embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } - -[profile.release] -debug = 2 -codegen-units = 1 -incremental = false -lto = "fat" -opt-level = 's' # try `s` or `z`, sometimes one is smaller, sometimes the other. - diff --git a/reloader/app/Cargo.toml b/reloader/app/Cargo.toml deleted file mode 100644 index 83c528f..0000000 --- a/reloader/app/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -edition = "2021" -name = "reloader-embassy" -version = "0.1.0" -license = "MIT OR Apache-2.0" -build = "build.rs" - -[dependencies] -embassy-futures = { version = "0.1.0" } -futures = { version = "0.3", default-features = false, features = ["async-await"]} -embassy-embedded-hal = { version = "0.1.0", default-features = false, features = ["defmt"] } -embassy-sync = { version = "0.2.0" } -embassy-executor = { version = "0.2.0", features = ["arch-cortex-m", "executor-thread", "nightly", "defmt", "integrated-timers", "executor-interrupt"] } -embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits"] } -embassy-nrf = { version = "0.1.0", features = ["defmt", "nrf52832", "time-driver-rtc1", "gpiote", "nightly", "unstable-pac", "time", "unstable-traits", "nfc-pins-as-gpio"] } -embassy-boot-nrf = { version = "0.1.0", features = ["nightly"] } -embassy-boot = { version = "0.1.0", features = ["nightly"] } -embedded-io = "0.4.0" -embedded-storage = "0.3.0" -embedded-hal = "1.0.0-rc.1" -pinetime-flash = { version = "0.1.0", path = "../../pinetime-flash", features = ["defmt"] } - -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } - -static_cell = "1.1" -cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -cortex-m-rt = "0.7.3" -heapless = "0.7" diff --git a/reloader/app/build.rs b/reloader/app/build.rs deleted file mode 100644 index a251716..0000000 --- a/reloader/app/build.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! This build script copies the `memory.x` file from the crate root into -//! a directory where the linker can always find it at build time. -//! For many projects this is optional, as the linker always searches the -//! project root directory -- wherever `Cargo.toml` is. However, if you -//! are using a workspace or have a more complicated build setup, this -//! build script becomes required. Additionally, by requesting that -//! Cargo re-run the build script whenever `memory.x` is changed, -//! updating `memory.x` ensures a rebuild of the application with the -//! new memory settings. - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - - println!("cargo:rustc-link-search={}", out.display()); - - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); - println!("cargo:rerun-if-changed=application.bin"); - println!("cargo:rerun-if-changed=bootloader.bin"); - println!("cargo:rerun-if-changed=softdevice.bin"); - - println!("cargo:rustc-link-arg-bins=--nmagic"); - println!("cargo:rustc-link-arg-bins=-Tlink.x"); - println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); -} diff --git a/reloader/app/memory.x b/reloader/app/memory.x deleted file mode 100644 index bc90159..0000000 --- a/reloader/app/memory.x +++ /dev/null @@ -1,21 +0,0 @@ -MEMORY -{ - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - MBR : ORIGIN = 0x00000000, LENGTH = 4K - SOFTDEVICE : ORIGIN = 0x00001000, LENGTH = 148K - FLASH : ORIGIN = 0x00026000, LENGTH = 324K - BOOTLOADER : ORIGIN = 0x00077000, LENGTH = 32K - BOOTLOADER_STATE : ORIGIN = 0x0007F000, LENGTH = 4K - - DFU : ORIGIN = 0x00000000, LENGTH = 328K - - RAM : ORIGIN = 0x2000BAF0, LENGTH = 17680 -} - -__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); -__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); - -__bootloader_dfu_start = ORIGIN(DFU); -__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); - -__bootloader_start = ORIGIN(BOOTLOADER); diff --git a/reloader/app/src/main.rs b/reloader/app/src/main.rs deleted file mode 100644 index ddf25e2..0000000 --- a/reloader/app/src/main.rs +++ /dev/null @@ -1,152 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![no_main] -#![feature(type_alias_impl_trait)] - -use core::cell::RefCell; - -use defmt_rtt as _; -use embassy_boot_nrf::{AlignedBuffer, BlockingFirmwareState as FirmwareState}; -use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; -use embassy_executor::{InterruptExecutor, Spawner}; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::interrupt::{InterruptExt, Priority}; -use embassy_nrf::nvmc::Nvmc; -use embassy_nrf::spis::MODE_3; -use embassy_nrf::{bind_interrupts, interrupt, pac, peripherals, spim}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::blocking_mutex::Mutex; -use embassy_time::{Duration, Timer}; -use embedded_storage::nor_flash::NorFlash; -use pinetime_flash::XtFlash; - -bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler; - -}); - -static SOFTDEVICE: &[u8] = include_bytes!("../softdevice.bin"); -static BOOTLOADER: &[u8] = include_bytes!("../bootloader.bin"); -static APPLICATION: &[u8] = include_bytes!("../application.bin"); - -const BOOTLOADER_DEST: u32 = 0x00077000; -const BOOTLOADER_STATE: u32 = 0x0007F000; -const APPLICATION_DEST: u32 = 0x00000000; // External flash -const SOFTDEVICE_DEST: u32 = 0x00000000; -const UICR_ADDRESS: u32 = 0x10001014; - -#[interrupt] -unsafe fn SWI0_EGU0() { - EXECUTOR_MED.on_interrupt() -} - -static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); - -#[embassy_executor::main] -async fn main(s: Spawner) { - let p = embassy_nrf::init(Default::default()); - - // Medium-priority executor: SWI0_EGU0, priority level 7 - interrupt::SWI0_EGU0.set_priority(Priority::P6); - let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); - spawner.spawn(watchdog_task()).unwrap(); - - defmt::info!("Hello! Starting reloader"); - let mut led = Output::new(p.P0_22, Level::Low, OutputDrive::Standard); - - Timer::after(Duration::from_secs(1)).await; - - let mut default_config = spim::Config::default(); - default_config.frequency = spim::Frequency::M8; - default_config.mode = MODE_3; - - let spim = spim::Spim::new(p.TWISPI0, Irqs, p.P0_02, p.P0_04, p.P0_03, default_config); - let spi_bus: Mutex> = Mutex::new(RefCell::new(spim)); - - // Create flash device - let flash_cs = Output::new(p.P0_05, Level::High, OutputDrive::Standard); - let flash_spi = SpiDevice::new(&spi_bus, flash_cs); - let mut external_flash = XtFlash::new(flash_spi).unwrap(); - external_flash.erase(0, 4 * 1024 * 1024).unwrap(); - Timer::after(Duration::from_secs(1)).await; - - external_flash.write(APPLICATION_DEST, APPLICATION).unwrap(); - Timer::after(Duration::from_secs(1)).await; - - defmt::info!("Flashed application"); - let mut internal_flash = Nvmc::new(p.NVMC); - - internal_flash.erase(0, 0x26000).unwrap(); - Timer::after(Duration::from_secs(1)).await; - defmt::info!("Erased softdevice section"); - - internal_flash.write(SOFTDEVICE_DEST, SOFTDEVICE).unwrap(); - Timer::after(Duration::from_secs(1)).await; - - defmt::info!("Flashed softdevice, erasing bootloader at {:x}", BOOTLOADER_DEST); - - internal_flash.erase(BOOTLOADER_DEST, BOOTLOADER_DEST + 32768).unwrap(); - internal_flash.erase(BOOTLOADER_STATE, BOOTLOADER_STATE + 4096).unwrap(); - Timer::after(Duration::from_secs(1)).await; - - defmt::info!("Erased bootloader, flashing it (size {})", BOOTLOADER.len()); - - internal_flash.write(BOOTLOADER_DEST, BOOTLOADER).unwrap(); - Timer::after(Duration::from_secs(1)).await; - - defmt::info!("Flashed bootloader"); - - unsafe { - let uicr = UICR_ADDRESS as *mut u32; - - // Enable NVMC so we can write UICR - let nvmc = unsafe { &*pac::NVMC::ptr() }; - nvmc.config.write(|w| w.wen().wen()); - while nvmc.ready.read().ready().is_busy() {} - core::ptr::write_volatile(uicr, BOOTLOADER_DEST); - nvmc.config.write(|w| w.wen().ren()); - while nvmc.ready.read().ready().is_busy() {} - - // Read back to confirm - let val = core::ptr::read_volatile(uicr); - defmt::info!("Wrote UICR: {:x}", val); - } - - let mtx = Mutex::new(RefCell::new(internal_flash)); - let part: BlockingPartition = BlockingPartition::new(&mtx, BOOTLOADER_STATE, 4096); - let mut aligned = AlignedBuffer([0; 4]); - let mut state = FirmwareState::new(part, &mut aligned.0); - match state.mark_updated() { - Ok(_) => { - defmt::info!("Marked as updated, resetting in 5 seconds!"); - Timer::after(Duration::from_secs(5)).await; - cortex_m::peripheral::SCB::sys_reset(); - } - Err(e) => { - defmt::info!("Error marking firmware as updated: {:?}", defmt::Debug2Format(&e)); - - loop { - led.set_low(); - Timer::after(Duration::from_millis(100)).await; - led.set_high(); - Timer::after(Duration::from_millis(100)).await; - } - } - } -} - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - cortex_m::asm::udf(); -} - -// Keeps our system alive -#[embassy_executor::task] -async fn watchdog_task() { - let mut handle = unsafe { embassy_nrf::wdt::WatchdogHandle::steal(0) }; - loop { - handle.pet(); - Timer::after(Duration::from_secs(2)).await; - defmt::info!("PET"); - } -} diff --git a/reloader/boot/Cargo.toml b/reloader/boot/Cargo.toml deleted file mode 100644 index 2489bb3..0000000 --- a/reloader/boot/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -edition = "2021" -name = "reloader-bootloader" -version = "0.1.0" -license = "MIT OR Apache-2.0" - -[dependencies] -embassy-nrf = { version = "0.1.0", default-features = false, features = ["rt", "nrf52832"] } - -static_cell = "1.1" -cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -cortex-m-rt = "0.7.3" diff --git a/reloader/boot/build.rs b/reloader/boot/build.rs deleted file mode 100644 index cd1a264..0000000 --- a/reloader/boot/build.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! This build script copies the `memory.x` file from the crate root into -//! a directory where the linker can always find it at build time. -//! For many projects this is optional, as the linker always searches the -//! project root directory -- wherever `Cargo.toml` is. However, if you -//! are using a workspace or have a more complicated build setup, this -//! build script becomes required. Additionally, by requesting that -//! Cargo re-run the build script whenever `memory.x` is changed, -//! updating `memory.x` ensures a rebuild of the application with the -//! new memory settings. - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); - - println!("cargo:rustc-link-arg-bins=--nmagic"); - println!("cargo:rustc-link-arg-bins=-Tlink.x"); -} diff --git a/reloader/boot/memory.x b/reloader/boot/memory.x deleted file mode 100644 index fdaa305..0000000 --- a/reloader/boot/memory.x +++ /dev/null @@ -1,11 +0,0 @@ -MEMORY -{ - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - FLASH : ORIGIN = 0x00008020, LENGTH = 32K - /*FLASH : ORIGIN = 0x00000000, LENGTH = 32K*/ - RELOADER : ORIGIN = 0x00026000, LENGTH = 343K - - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K -} - -__reloader_start = ORIGIN(RELOADER); diff --git a/reloader/boot/src/main.rs b/reloader/boot/src/main.rs deleted file mode 100644 index 9a5e884..0000000 --- a/reloader/boot/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![no_std] -#![no_main] - -use cortex_m_rt::{entry, exception}; -use embassy_nrf as _; - -#[entry] -fn main() -> ! { - unsafe { - extern "C" { - static __reloader_start: u32; - } - let start = &__reloader_start as *const u32 as u32; - - let mut p = cortex_m::Peripherals::steal(); - p.SCB.invalidate_icache(); - p.SCB.vtor.write(start); - - cortex_m::asm::bootload(start as *const u32) - } -} - -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] -unsafe extern "C" fn HardFault() { - cortex_m::peripheral::SCB::sys_reset(); -} - -#[exception] -unsafe fn DefaultHandler(_: i16) -> ! { - const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; - - panic!("DefaultHandler #{:?}", irqn); -} - -#[cfg(not(feature = "panic-probe"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - cortex_m::asm::udf(); -} From c6a07c0e36e9e1edf46423898dd2680a87310e67 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:25:20 +0100 Subject: [PATCH 19/21] Update readme --- README.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6654fea..da78534 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ Firmware for Pinetime based on [Embassy](https://embassy.dev). The goal is to pr * Rollback to previous firmware if reset or crashing before new firmware is validated in watch UI. * Compatible with existing InfiniTime bootloader. -Some features that has been removed after recent switch to mcuboot, but will be added again soon: +NOTE: Some features that has been removed after recent switch to mcuboot, but will be added again soon: + +* DFU: Implements Nordic DFU protocol so you can update from a phone app such as nRF Connect to perform firmware updates. -* Implements Nordic DFU protocol so you can update from a phone app such as nRF Connect to perform firmware updates. ## Getting started @@ -38,18 +39,8 @@ cd firmware cargo run --release --features panic-probe,baremetal ``` -## Updating firmware - -Once you have Watchful running, you can use an app such as GadgetBridge nRF Connect on Android or iOS using the DFU functionality with the [latest release](https://github.com/lulf/watchful/releases). - -## *DANGER* Reflashing your sealed PineTime from InfiniTime to Watchful - -If you want to reflash your sealed PineTime to Watchful, it is possible. But there is a chance to brick your PineTime, so don't do this unless you've tried it a few times on a devkit and feel confident. Also consider the fact that once you go to Watchful, there is no way to go back at the moment. - -*I take no responsibilty of broken PineTimes, you are hereby warned :)* +## Recovering from older versions of Watchful -With that out of the way, +NOTE: If you've used watchful before, it now has switched from using `embassy-boot` to `mcuboot` as provided by default on InfiniTime. To achieve that, the [nrf-softdevice](https://github.com/embassy-rs/nrf-softdevice/) has been replaced with [trouble](https://github.com/embassy-rs/trouble). -* Update your PineTime to Infinity 1.13.0 -* Download the `watchful-reloader` from the [latest release](https://github.com/lulf/watchful/releases) -* Use whatever [update mechanism that works with InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime/blob/main/doc/gettingStarted/updating-software.md). +The `infinitime-recovery` app allows you to move from previous versions of Watchful to the new. From 9c0428ddca32b87dcdfc54a025452b7caae63cc8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:43:56 +0100 Subject: [PATCH 20/21] Remove unused --- firmware/src/ble.rs | 49 --------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/firmware/src/ble.rs b/firmware/src/ble.rs index 2be6338..70df8b7 100644 --- a/firmware/src/ble.rs +++ b/firmware/src/ble.rs @@ -58,55 +58,6 @@ pub struct PineTimeServer { uart: NrfUartService, } -/* -#[gatt_client(uuid = "1805")] -struct CurrentTimeServiceClient { - #[characteristic(uuid = "2a2b", write, read, notify)] - current_time: Vec, -} -pub async fn sync_time(conn: &Connection, clock: &crate::clock::Clock) { - if let Ok(time_client) = gatt_client::discover::(&conn).await { - info!("Found time server on peer, synchronizing time"); - match time_client.get_time().await { - Ok(time) => { - // info!("Got time from peer: {:?}", defmt::Debug2Format(&time)); - clock.set(time); - } - Err(e) => { - info!("Error retrieving time: {:?}", e); - } - } - } -} - -impl CurrentTimeServiceClient { - pub async fn get_time(&self) -> Result { - let data = self.current_time_read().await?; - if data.len() == 10 { - let year = u16::from_le_bytes([data[0], data[1]]); - let month = data[2]; - let day = data[3]; - let hour = data[4]; - let minute = data[5]; - let second = data[6]; - let _weekday = data[7]; - let secs_frac = data[8]; - - if let Ok(month) = month.try_into() { - let date = time::Date::from_calendar_date(year as i32, month, day); - let micros = secs_frac as u32 * 1000000 / 256; - let time = time::Time::from_hms_micro(hour, minute, second, micros); - if let (Ok(time), Ok(date)) = (time, date) { - let dt = time::PrimitiveDateTime::new(date, time); - return Ok(dt); - } - } - } - Err(gatt_client::ReadError::Truncated) - } -} -*/ - impl PineTimeServer<'_, '_, NrfController> { pub async fn handle( &self, From 1fa90a636d8ca47fae26a61adfbbda7d421c6bec Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 12 Dec 2024 11:45:35 +0100 Subject: [PATCH 21/21] Licensing --- LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 25 ++++++ README.md | 11 +++ 3 files changed, 237 insertions(+) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..8f7956e --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) Embassy project contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..1fe5730 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) Embassy project contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index da78534..e6c1844 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,14 @@ cargo run --release --features panic-probe,baremetal NOTE: If you've used watchful before, it now has switched from using `embassy-boot` to `mcuboot` as provided by default on InfiniTime. To achieve that, the [nrf-softdevice](https://github.com/embassy-rs/nrf-softdevice/) has been replaced with [trouble](https://github.com/embassy-rs/trouble). The `infinitime-recovery` app allows you to move from previous versions of Watchful to the new. + +## License + +Code in `tools/mcuboot` are subject to mcuboot licensing. + +Watchful is licensed under either of + +* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option.