Repo for designs & driver for a TA7642 powered lightning detector

feat: Embassy driver #1

merged opened by sachy.dev targeting main from driver
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:usjm3ynnir6y4inkcdovrfei/sh.tangled.repo.pull/3mcxaimss3u22
+962 -1
Diff #5
+21
.tangled/workflows/test.yml
··· 1 + when: 2 + - event: ["push", "pull_request"] 3 + branch: main 4 + 5 + engine: nixery 6 + 7 + dependencies: 8 + nixpkgs: 9 + - clang 10 + - cargo 11 + - rustfmt 12 + - protobuf 13 + - cargo-nextest 14 + 15 + steps: 16 + - name: Format check 17 + command: cargo fmt --all --check 18 + - name: Tests 19 + command: cargo nextest run --workspace --locked --no-fail-fast 20 + - name: Doc Tests 21 + command: cargo test --workspace --locked --doc --no-fail-fast
+266
Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "byteorder" 7 + version = "1.5.0" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 10 + 11 + [[package]] 12 + name = "cfg-if" 13 + version = "1.0.4" 14 + source = "registry+https://github.com/rust-lang/crates.io-index" 15 + checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 16 + 17 + [[package]] 18 + name = "critical-section" 19 + version = "1.2.0" 20 + source = "registry+https://github.com/rust-lang/crates.io-index" 21 + checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 22 + 23 + [[package]] 24 + name = "document-features" 25 + version = "0.2.12" 26 + source = "registry+https://github.com/rust-lang/crates.io-index" 27 + checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" 28 + dependencies = [ 29 + "litrs", 30 + ] 31 + 32 + [[package]] 33 + name = "embassy-executor-timer-queue" 34 + version = "0.1.0" 35 + source = "registry+https://github.com/rust-lang/crates.io-index" 36 + checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" 37 + 38 + [[package]] 39 + name = "embassy-strike-driver" 40 + version = "0.1.0" 41 + dependencies = [ 42 + "critical-section", 43 + "embassy-sync", 44 + "embassy-time", 45 + "heapless 0.9.2", 46 + "pollster", 47 + ] 48 + 49 + [[package]] 50 + name = "embassy-sync" 51 + version = "0.7.2" 52 + source = "registry+https://github.com/rust-lang/crates.io-index" 53 + checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" 54 + dependencies = [ 55 + "cfg-if", 56 + "critical-section", 57 + "embedded-io-async", 58 + "futures-core", 59 + "futures-sink", 60 + "heapless 0.8.0", 61 + ] 62 + 63 + [[package]] 64 + name = "embassy-time" 65 + version = "0.5.0" 66 + source = "registry+https://github.com/rust-lang/crates.io-index" 67 + checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" 68 + dependencies = [ 69 + "cfg-if", 70 + "critical-section", 71 + "document-features", 72 + "embassy-time-driver", 73 + "embassy-time-queue-utils", 74 + "embedded-hal 0.2.7", 75 + "embedded-hal 1.0.0", 76 + "embedded-hal-async", 77 + "futures-core", 78 + ] 79 + 80 + [[package]] 81 + name = "embassy-time-driver" 82 + version = "0.2.1" 83 + source = "registry+https://github.com/rust-lang/crates.io-index" 84 + checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" 85 + dependencies = [ 86 + "document-features", 87 + ] 88 + 89 + [[package]] 90 + name = "embassy-time-queue-utils" 91 + version = "0.3.0" 92 + source = "registry+https://github.com/rust-lang/crates.io-index" 93 + checksum = "80e2ee86063bd028a420a5fb5898c18c87a8898026da1d4c852af2c443d0a454" 94 + dependencies = [ 95 + "embassy-executor-timer-queue", 96 + "heapless 0.8.0", 97 + ] 98 + 99 + [[package]] 100 + name = "embedded-hal" 101 + version = "0.2.7" 102 + source = "registry+https://github.com/rust-lang/crates.io-index" 103 + checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 104 + dependencies = [ 105 + "nb 0.1.3", 106 + "void", 107 + ] 108 + 109 + [[package]] 110 + name = "embedded-hal" 111 + version = "1.0.0" 112 + source = "registry+https://github.com/rust-lang/crates.io-index" 113 + checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" 114 + 115 + [[package]] 116 + name = "embedded-hal-async" 117 + version = "1.0.0" 118 + source = "registry+https://github.com/rust-lang/crates.io-index" 119 + checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" 120 + dependencies = [ 121 + "embedded-hal 1.0.0", 122 + ] 123 + 124 + [[package]] 125 + name = "embedded-io" 126 + version = "0.6.1" 127 + source = "registry+https://github.com/rust-lang/crates.io-index" 128 + checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" 129 + 130 + [[package]] 131 + name = "embedded-io-async" 132 + version = "0.6.1" 133 + source = "registry+https://github.com/rust-lang/crates.io-index" 134 + checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" 135 + dependencies = [ 136 + "embedded-io", 137 + ] 138 + 139 + [[package]] 140 + name = "futures-core" 141 + version = "0.3.31" 142 + source = "registry+https://github.com/rust-lang/crates.io-index" 143 + checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 144 + 145 + [[package]] 146 + name = "futures-sink" 147 + version = "0.3.31" 148 + source = "registry+https://github.com/rust-lang/crates.io-index" 149 + checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 150 + 151 + [[package]] 152 + name = "hash32" 153 + version = "0.3.1" 154 + source = "registry+https://github.com/rust-lang/crates.io-index" 155 + checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" 156 + dependencies = [ 157 + "byteorder", 158 + ] 159 + 160 + [[package]] 161 + name = "heapless" 162 + version = "0.8.0" 163 + source = "registry+https://github.com/rust-lang/crates.io-index" 164 + checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" 165 + dependencies = [ 166 + "hash32", 167 + "stable_deref_trait", 168 + ] 169 + 170 + [[package]] 171 + name = "heapless" 172 + version = "0.9.2" 173 + source = "registry+https://github.com/rust-lang/crates.io-index" 174 + checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" 175 + dependencies = [ 176 + "hash32", 177 + "stable_deref_trait", 178 + ] 179 + 180 + [[package]] 181 + name = "litrs" 182 + version = "1.0.0" 183 + source = "registry+https://github.com/rust-lang/crates.io-index" 184 + checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" 185 + 186 + [[package]] 187 + name = "nb" 188 + version = "0.1.3" 189 + source = "registry+https://github.com/rust-lang/crates.io-index" 190 + checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 191 + dependencies = [ 192 + "nb 1.1.0", 193 + ] 194 + 195 + [[package]] 196 + name = "nb" 197 + version = "1.1.0" 198 + source = "registry+https://github.com/rust-lang/crates.io-index" 199 + checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 200 + 201 + [[package]] 202 + name = "pollster" 203 + version = "0.4.0" 204 + source = "registry+https://github.com/rust-lang/crates.io-index" 205 + checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" 206 + dependencies = [ 207 + "pollster-macro", 208 + ] 209 + 210 + [[package]] 211 + name = "pollster-macro" 212 + version = "0.4.0" 213 + source = "registry+https://github.com/rust-lang/crates.io-index" 214 + checksum = "ac5da421106a50887c5b51d20806867db377fbb86bacf478ee0500a912e0c113" 215 + dependencies = [ 216 + "proc-macro2", 217 + "quote", 218 + "syn", 219 + ] 220 + 221 + [[package]] 222 + name = "proc-macro2" 223 + version = "1.0.106" 224 + source = "registry+https://github.com/rust-lang/crates.io-index" 225 + checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" 226 + dependencies = [ 227 + "unicode-ident", 228 + ] 229 + 230 + [[package]] 231 + name = "quote" 232 + version = "1.0.44" 233 + source = "registry+https://github.com/rust-lang/crates.io-index" 234 + checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" 235 + dependencies = [ 236 + "proc-macro2", 237 + ] 238 + 239 + [[package]] 240 + name = "stable_deref_trait" 241 + version = "1.2.1" 242 + source = "registry+https://github.com/rust-lang/crates.io-index" 243 + checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 244 + 245 + [[package]] 246 + name = "syn" 247 + version = "2.0.114" 248 + source = "registry+https://github.com/rust-lang/crates.io-index" 249 + checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" 250 + dependencies = [ 251 + "proc-macro2", 252 + "quote", 253 + "unicode-ident", 254 + ] 255 + 256 + [[package]] 257 + name = "unicode-ident" 258 + version = "1.0.22" 259 + source = "registry+https://github.com/rust-lang/crates.io-index" 260 + checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 261 + 262 + [[package]] 263 + name = "void" 264 + version = "1.0.2" 265 + source = "registry+https://github.com/rust-lang/crates.io-index" 266 + checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+16
Cargo.toml
··· 1 + [workspace] 2 + resolver = "3" 3 + members = ["embassy-strike-driver"] 4 + 5 + [workspace.package] 6 + authors = ["Sachy.dev <sachymetsu@tutamail.com>"] 7 + edition = "2024" 8 + repository = "https://tangled.org/sachy.dev/strike-sensor" 9 + version = "0.1.0" 10 + license = "AGPL-3.0-only" 11 + rust-version = "1.91.0" 12 + 13 + [workspace.dependencies] 14 + embassy-time = "0.5" 15 + embassy-sync = "0.7" 16 + defmt = "1"
+5 -1
README.md
··· 4 4 5 5 The sensor designs can be found in the [kicad](./kicad) folder. 6 6 7 + ## Driver 8 + 9 + Currently, the driver needs to be tested and coded according to how the new PCB/circuit behaves, so this will require a bit of work before considered "ready". 10 + 7 11 ## Licenses 8 12 9 - The sensor hardware designs are licensed under the [CERN Open Hardware Licence Version 2 - Strongly Reciprocal](./kicad/LICENSE-CERN-OHL-S) license. 13 + The sensor hardware designs are licensed under the [CERN Open Hardware Licence Version 2 - Strongly Reciprocal](./kicad/LICENSE-CERN-OHL-S) license. ⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢
+23
embassy-strike-driver/Cargo.toml
··· 1 + [package] 2 + name = "embassy-strike-driver" 3 + authors.workspace = true 4 + edition.workspace = true 5 + repository.workspace = true 6 + version.workspace = true 7 + license.workspace = true 8 + rust-version.workspace = true 9 + 10 + [features] 11 + default = [] 12 + alloc = [] 13 + heapless = ["dep:heapless"] 14 + 15 + [dependencies] 16 + embassy-time.workspace = true 17 + embassy-sync.workspace = true 18 + heapless = { version = "0.9.2", optional = true } 19 + 20 + [dev-dependencies] 21 + embassy-time = { workspace = true, features = ["mock-driver", "generic-queue-8"] } 22 + critical-section = { version = "1.1", features = ["std"] } 23 + pollster = { version = "0.4", features = ["macro"] }
+29
embassy-strike-driver/src/analysis.rs
··· 1 + use crate::{BLOCK_SIZE, traits::BufferMut}; 2 + 3 + pub fn analyse_buffer_by_stepped_windows<B: BufferMut<usize>>( 4 + threshold: u16, 5 + buf: &[u16], 6 + average: u16, 7 + peaks: &mut B, 8 + ) -> u16 { 9 + const CHUNK_SIZE: usize = BLOCK_SIZE / 32; 10 + const CHUNK_STEP: usize = CHUNK_SIZE / 2; 11 + 12 + let mut total = 0u32; 13 + let mut len = 0u32; 14 + 15 + for (i, window) in buf.windows(CHUNK_SIZE).enumerate().step_by(CHUNK_STEP) { 16 + let window_total = window.iter().copied().sum::<u16>(); 17 + let window_avg = window_total / CHUNK_SIZE as u16; 18 + let diff = average.saturating_sub(window_avg); 19 + 20 + if diff > threshold { 21 + peaks.push(i); 22 + } else { 23 + total += window_total as u32; 24 + len += CHUNK_SIZE as u32; 25 + } 26 + } 27 + 28 + (total / len) as u16 29 + }
+534
embassy-strike-driver/src/lib.rs
··· 1 + //! A generalised Embassy driver for the Strike Sensor v1 2 + //! ⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢ 3 + #![no_std] 4 + 5 + #[cfg(feature = "alloc")] 6 + extern crate alloc; 7 + 8 + mod analysis; 9 + pub mod traits; 10 + 11 + use core::cell::Cell; 12 + 13 + use embassy_sync::{ 14 + blocking_mutex::raw::NoopRawMutex, 15 + zerocopy_channel::{Channel, Receiver, Sender}, 16 + }; 17 + use embassy_time::{Duration, Instant, Ticker, Timer}; 18 + 19 + use crate::traits::{AdcSource, BufferMut, PwmSource, TimeSource}; 20 + 21 + pub const BLOCK_SIZE: usize = 512; 22 + pub type ZeroCopyChannel<'device> = Channel<'device, NoopRawMutex, (i64, [u16; BLOCK_SIZE])>; 23 + 24 + #[derive(Debug)] 25 + struct DetectorState { 26 + max_duty: Cell<u8>, 27 + duty: Cell<u8>, 28 + avg: Cell<u16>, 29 + strikes: Cell<u16>, 30 + warn_level: Cell<u16>, 31 + } 32 + 33 + impl Default for DetectorState { 34 + fn default() -> Self { 35 + Self { 36 + max_duty: Cell::new(0), 37 + duty: Cell::new(0), 38 + avg: Cell::new(0), 39 + strikes: Cell::new(0), 40 + warn_level: Cell::new(255), 41 + } 42 + } 43 + } 44 + 45 + #[derive(Debug)] 46 + pub struct DetectorConfig { 47 + blip_threshold: Cell<u16>, 48 + blip_size: Cell<usize>, 49 + } 50 + 51 + impl Default for DetectorConfig { 52 + fn default() -> Self { 53 + Self { 54 + blip_threshold: Cell::new(14), 55 + blip_size: Cell::new(2), 56 + } 57 + } 58 + } 59 + 60 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 61 + pub enum DetectorUpdate<'a> { 62 + Tick { 63 + timestamp: i64, 64 + level: u16, 65 + }, 66 + Detection { 67 + timestamp: i64, 68 + samples: &'a [u16], 69 + peaks: &'a [usize], 70 + }, 71 + } 72 + 73 + pub struct DetectorDriver<T: TimeSource, P: PwmSource, A: AdcSource> { 74 + state: DetectorState, 75 + config: DetectorConfig, 76 + timer_source: T, 77 + pwm: P, 78 + adc: A, 79 + } 80 + 81 + impl<T, P, A> DetectorDriver<T, P, A> 82 + where 83 + T: TimeSource, 84 + P: PwmSource, 85 + A: AdcSource, 86 + { 87 + pub fn new(config: DetectorConfig, timer_source: T, pwm: P, adc: A) -> Self { 88 + Self { 89 + state: Default::default(), 90 + config, 91 + timer_source, 92 + pwm, 93 + adc, 94 + } 95 + } 96 + 97 + pub fn reset_timer_source(&mut self) { 98 + self.timer_source = T::get_source(); 99 + } 100 + 101 + pub fn get_timestamp(&self) -> i64 { 102 + self.timer_source.timestamp() 103 + } 104 + 105 + pub fn set_blip_threshold(&self, threshold: u16) { 106 + self.config.blip_threshold.set(threshold); 107 + } 108 + 109 + pub fn set_blip_size(&self, size: usize) { 110 + self.config.blip_size.set(size); 111 + } 112 + 113 + pub async fn tune(&mut self, samples: &mut [u16]) { 114 + // info!("Tuning Detector for correct voltage settings"); 115 + let mut duty = 0; 116 + self.pwm.set_duty(duty); 117 + Timer::after_secs(2).await; 118 + let mut act_value = self.adc.sample_average(samples).await; 119 + 120 + // info!("initial ACT: {}", act_value); 121 + 122 + while act_value < 1364 { 123 + duty += 2; 124 + if duty >= 256 { 125 + duty = 0; 126 + self.pwm.set_duty(duty); 127 + Timer::after_secs(2).await; 128 + act_value = self.adc.sample_average(samples).await; 129 + // info!("Restarting tuning"); 130 + continue; 131 + } 132 + self.pwm.set_duty(duty); 133 + Timer::after_millis(250).await; 134 + act_value = self.adc.sample_average(samples).await; 135 + // info!("ACT: {}, Duty: {}", act_value, duty); 136 + } 137 + self.state.max_duty.set(duty as u8); 138 + duty = (duty / 3) * 2; 139 + self.pwm.set_duty(duty); 140 + self.state.duty.set(duty as u8); 141 + // info!("Set detection duty to: {}", duty); 142 + // Allow voltage level to stabilize after tuning 143 + Timer::after_secs(2).await; 144 + let avg = self.adc.sample_average(samples).await; 145 + self.state.avg.set(avg); 146 + } 147 + 148 + /// Samples and returns an `i64` timestamp. 149 + pub async fn sample_with_zerocopy<'a>( 150 + &self, 151 + dma: &mut Sender<'a, NoopRawMutex, (i64, [u16; BLOCK_SIZE])>, 152 + ) { 153 + loop { 154 + let (time, samples) = dma.send().await; 155 + *time = self.timer_source.timestamp(); 156 + self.adc.sample(samples).await; 157 + dma.send_done(); 158 + } 159 + } 160 + 161 + pub fn detect_from_sample<B, F>( 162 + &self, 163 + timestamp: i64, 164 + samples: &[u16], 165 + peaks: &mut B, 166 + update: F, 167 + ) where 168 + B: BufferMut<usize>, 169 + F: Fn(DetectorUpdate<'_>), 170 + { 171 + peaks.clear(); 172 + 173 + let new_avg = analysis::analyse_buffer_by_stepped_windows( 174 + self.config.blip_threshold.get(), 175 + samples, 176 + self.state.avg.get(), 177 + peaks, 178 + ); 179 + 180 + let blips = peaks.len(); 181 + 182 + if blips >= self.config.blip_size.get() { 183 + self.state 184 + .strikes 185 + .update(|strike| strike.saturating_add(32)); 186 + 187 + update(DetectorUpdate::Detection { 188 + timestamp, 189 + samples, 190 + peaks: peaks.as_slice(), 191 + }); 192 + } 193 + 194 + self.state.avg.set(new_avg); 195 + } 196 + 197 + pub async fn detect_with_zerocopy<'a, 'd, B, F>( 198 + &self, 199 + dma: &mut Receiver<'a, NoopRawMutex, (i64, [u16; BLOCK_SIZE])>, 200 + peaks: &'d mut B, 201 + update: F, 202 + ) where 203 + B: BufferMut<usize>, 204 + F: Fn(DetectorUpdate<'_>), 205 + { 206 + loop { 207 + let (timestamp, samples) = dma.receive().await; 208 + 209 + self.detect_from_sample(*timestamp, samples, peaks, &update); 210 + 211 + dma.receive_done(); 212 + } 213 + } 214 + 215 + pub async fn tick<F>(&self, update: F) 216 + where 217 + F: Fn(DetectorUpdate), 218 + { 219 + let mut inactive: Option<Instant> = None; 220 + let mut interval = Ticker::every(Duration::from_secs(1)); 221 + 222 + loop { 223 + interval.next().await; 224 + let strikes = self.state.strikes.get(); 225 + let mut warn_level = self.state.warn_level.get(); 226 + 227 + if strikes > 32 { 228 + warn_level = warn_level.saturating_add(strikes); 229 + } 230 + 231 + let decay = warn_level >> 8; 232 + 233 + self.state.strikes.set(0); 234 + self.state.warn_level.set(warn_level - decay); 235 + 236 + match inactive { 237 + Some(_) if decay > 0 => { 238 + inactive = None; 239 + } 240 + Some(val) if val.elapsed() >= Duration::from_secs(3600) => break, 241 + None if decay == 0 => { 242 + inactive = Some(Instant::now()); 243 + } 244 + None => { 245 + update(DetectorUpdate::Tick { 246 + timestamp: self.timer_source.timestamp(), 247 + level: warn_level - 255, 248 + }); 249 + } 250 + _ => continue, 251 + } 252 + } 253 + } 254 + } 255 + 256 + #[cfg(test)] 257 + mod tests { 258 + use core::future::poll_fn; 259 + use embassy_time::MockDriver; 260 + 261 + extern crate alloc; 262 + use super::*; 263 + 264 + #[derive(Debug, Default)] 265 + struct MockMachine { 266 + pwm: Cell<u16>, 267 + } 268 + 269 + impl MockMachine { 270 + fn adc_sample_avg(&self) -> u16 { 271 + self.pwm.get().saturating_mul(14) 272 + } 273 + } 274 + 275 + struct MockPwm<'a>(&'a MockMachine); 276 + 277 + impl PwmSource for MockPwm<'_> { 278 + fn set_duty(&mut self, duty: u16) { 279 + self.0.pwm.set(duty); 280 + } 281 + } 282 + 283 + struct MockAdc<'a>(&'a MockMachine); 284 + 285 + impl AdcSource for MockAdc<'_> { 286 + async fn sample(&self, samples: &mut [u16]) { 287 + samples.fill(self.0.adc_sample_avg()); 288 + } 289 + 290 + async fn sample_average(&self, _samples: &mut [u16]) -> u16 { 291 + self.0.adc_sample_avg() 292 + } 293 + } 294 + 295 + struct MockTimeSource; 296 + 297 + impl TimeSource for MockTimeSource { 298 + fn get_source() -> Self { 299 + Self 300 + } 301 + fn timestamp(&self) -> i64 { 302 + 0 303 + } 304 + } 305 + 306 + #[cfg(not(feature = "alloc"))] 307 + impl BufferMut<usize> for alloc::vec::Vec<usize> { 308 + fn push(&mut self, value: usize) { 309 + self.push(value); 310 + } 311 + 312 + fn clear(&mut self) { 313 + self.clear(); 314 + } 315 + 316 + fn len(&self) -> usize { 317 + self.len() 318 + } 319 + 320 + fn is_empty(&self) -> bool { 321 + self.is_empty() 322 + } 323 + 324 + fn as_slice(&self) -> &[usize] { 325 + self 326 + } 327 + } 328 + 329 + async fn tune_detector_manually<'a>( 330 + detector: &mut DetectorDriver<MockTimeSource, MockPwm<'a>, MockAdc<'a>>, 331 + buf: &mut [u16], 332 + driver: &MockDriver, 333 + ) { 334 + let mut tuning = core::pin::pin!(detector.tune(buf)); 335 + 336 + poll_fn(|cx| match tuning.as_mut().poll(cx) { 337 + core::task::Poll::Ready(_) => core::task::Poll::Ready(()), 338 + core::task::Poll::Pending => { 339 + cx.waker().wake_by_ref(); 340 + driver.advance(Duration::from_secs(2)); 341 + 342 + core::task::Poll::Pending 343 + } 344 + }) 345 + .await; 346 + } 347 + 348 + fn generate_signal(samples: &mut [u16]) { 349 + // Example voltage drop signal 350 + samples[5] -= 60; 351 + samples[6] -= 55; 352 + samples[7] -= 50; 353 + samples[8] -= 45; 354 + samples[9] -= 40; 355 + samples[10] -= 35; 356 + samples[11] -= 30; 357 + samples[12] -= 28; 358 + samples[13] -= 26; 359 + samples[14] -= 24; 360 + samples[15] -= 22; 361 + samples[16] -= 20; 362 + samples[17] -= 18; 363 + samples[18] -= 16; 364 + samples[19] -= 14; 365 + samples[20] -= 12; 366 + samples[21] -= 11; 367 + samples[22] -= 10; 368 + samples[23] -= 9; 369 + samples[24] -= 8; 370 + samples[25] -= 7; 371 + samples[26] -= 6; 372 + samples[27] -= 5; 373 + samples[28] -= 4; 374 + samples[29] -= 3; 375 + samples[30] -= 2; 376 + samples[31] -= 1; 377 + } 378 + 379 + #[pollster::test] 380 + async fn tuning_cycle_completes() { 381 + let driver = embassy_time::MockDriver::get(); 382 + driver.reset(); 383 + let device = MockMachine::default(); 384 + let pwm = MockPwm(&device); 385 + let adc = MockAdc(&device); 386 + 387 + let mut detector = DetectorDriver::new(Default::default(), MockTimeSource, pwm, adc); 388 + let mut buf = [0; 16]; 389 + 390 + tune_detector_manually(&mut detector, &mut buf, driver).await; 391 + 392 + assert_eq!(detector.state.max_duty.get(), 98); 393 + assert_eq!(detector.state.duty.get(), 64); 394 + assert_eq!(detector.adc.sample_average(&mut buf).await, 896); 395 + } 396 + 397 + #[pollster::test] 398 + async fn tick_updates_only_on_raised_levels() { 399 + let driver = embassy_time::MockDriver::get(); 400 + driver.reset(); 401 + let device = MockMachine::default(); 402 + let pwm = MockPwm(&device); 403 + let adc = MockAdc(&device); 404 + 405 + let detector = DetectorDriver::new(Default::default(), MockTimeSource, pwm, adc); 406 + 407 + detector.state.max_duty.set(98); 408 + detector.state.duty.set(64); 409 + detector.state.avg.set(896); 410 + 411 + { 412 + let mut tick = core::pin::pin!(detector.tick(|a| { 413 + assert_eq!( 414 + a, 415 + DetectorUpdate::Tick { 416 + timestamp: 0, 417 + level: 300 418 + } 419 + ); 420 + })); 421 + 422 + poll_fn(|cx| match tick.as_mut().poll(cx) { 423 + core::task::Poll::Ready(_) => core::task::Poll::Ready(()), 424 + core::task::Poll::Pending => { 425 + if detector.state.warn_level.get() > 255 { 426 + return core::task::Poll::Ready(()); 427 + } 428 + detector.state.strikes.set(300); 429 + driver.advance(Duration::from_secs(1)); 430 + cx.waker().wake_by_ref(); 431 + core::task::Poll::Pending 432 + } 433 + }) 434 + .await; 435 + } 436 + 437 + assert_eq!(detector.state.warn_level.get(), 553); 438 + } 439 + 440 + #[pollster::test] 441 + async fn detection_updates_only_on_large_enough_signals() { 442 + let driver = embassy_time::MockDriver::get(); 443 + driver.reset(); 444 + let device = MockMachine::default(); 445 + let pwm = MockPwm(&device); 446 + let adc = MockAdc(&device); 447 + 448 + let detector = DetectorDriver::new(Default::default(), MockTimeSource, pwm, adc); 449 + detector.pwm.0.pwm.set(64); 450 + detector.state.max_duty.set(98); 451 + detector.state.duty.set(64); 452 + detector.state.avg.set(896); 453 + 454 + let mut samples = alloc::vec![0; BLOCK_SIZE]; 455 + 456 + detector.adc.sample(&mut samples).await; 457 + 458 + samples[5] -= 3; 459 + samples[6] -= 1; 460 + 461 + let mut peaks = alloc::vec::Vec::with_capacity(512); 462 + 463 + let update = |_update: DetectorUpdate<'_>| { 464 + panic!("This update function shouldn't be called"); 465 + }; 466 + 467 + detector.detect_from_sample(0, &samples, &mut peaks, update); 468 + 469 + assert_eq!(peaks.len(), 0); 470 + 471 + generate_signal(&mut samples); 472 + 473 + let expected_peaks = alloc::vec![0, 8]; 474 + let called = Cell::new(false); 475 + 476 + let update = |update: DetectorUpdate<'_>| { 477 + called.set(true); 478 + assert_eq!( 479 + update, 480 + DetectorUpdate::Detection { 481 + timestamp: 0, 482 + samples: &samples, 483 + peaks: expected_peaks.as_slice() 484 + } 485 + ) 486 + }; 487 + 488 + detector.detect_from_sample(0, &samples, &mut peaks, update); 489 + 490 + assert_eq!(peaks.len(), 2); 491 + assert!(called.get()); 492 + } 493 + 494 + #[pollster::test] 495 + async fn detection_sensitivity_can_be_configured() { 496 + let driver = embassy_time::MockDriver::get(); 497 + driver.reset(); 498 + let device = MockMachine::default(); 499 + let pwm = MockPwm(&device); 500 + let adc = MockAdc(&device); 501 + 502 + let detector = DetectorDriver::new(Default::default(), MockTimeSource, pwm, adc); 503 + detector.pwm.0.pwm.set(64); 504 + detector.state.max_duty.set(98); 505 + detector.state.duty.set(64); 506 + detector.state.avg.set(896); 507 + 508 + let mut samples = alloc::vec![0; BLOCK_SIZE]; 509 + let mut peaks: alloc::vec::Vec<usize> = alloc::vec::Vec::with_capacity(BLOCK_SIZE); 510 + 511 + // Require bigger size blips. 512 + detector.config.blip_size.set(3); 513 + 514 + detector.adc.sample(&mut samples).await; 515 + generate_signal(&mut samples); 516 + 517 + detector.detect_from_sample(0, &samples, &mut peaks, |_update| { 518 + panic!("Update shouldn't be called"); 519 + }); 520 + 521 + assert_eq!(peaks.len(), 2); 522 + 523 + // Require bigger threshold for blip detection 524 + detector.config.blip_size.set(2); 525 + detector.config.blip_threshold.set(24); 526 + 527 + detector.detect_from_sample(0, &samples, &mut peaks, |_update| { 528 + panic!("Update shouldn't be called"); 529 + }); 530 + 531 + // Update didn't call because detected blip wasn't big enough 532 + assert_eq!(peaks.len(), 1); 533 + } 534 + }
+68
embassy-strike-driver/src/traits.rs
··· 1 + pub trait TimeSource { 2 + fn timestamp(&self) -> i64; 3 + fn get_source() -> Self; 4 + } 5 + 6 + pub trait AdcSource { 7 + fn sample_average(&self, samples: &mut [u16]) -> impl Future<Output = u16>; 8 + fn sample(&self, samples: &mut [u16]) -> impl Future<Output = ()>; 9 + } 10 + 11 + pub trait PwmSource { 12 + fn set_duty(&mut self, duty: u16); 13 + } 14 + 15 + /// A Mutable Buffer trait ⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁤⁢⁤⁤⁤⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁢⁤⁤⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁤⁢⁢⁤⁢⁢⁢⁤⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁤⁤⁢⁢⁤⁤⁢⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁤⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁤⁢⁤⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁤⁤⁢⁢⁢⁢⁢⁤⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁤⁤⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁤⁢⁤⁤⁤⁢⁤⁤⁤⁤⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁢⁢⁤⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁢⁤⁤⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁤⁢⁤⁢⁢⁤⁤⁢⁤⁢⁤⁢⁤⁢⁢⁢⁢⁤⁢⁤⁤⁢⁤⁢⁤⁢⁢⁢⁤⁤⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁤⁢⁢⁤⁤⁢⁢⁢⁤⁢⁢⁢⁤⁢⁤⁢⁢⁤⁢⁢⁢⁢⁤⁢⁢⁤⁢⁢⁤⁢⁢⁢⁤⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁤⁢⁤⁢⁢⁤⁢⁢⁢⁢⁢⁤⁢⁤⁢⁤⁢ 16 + pub trait BufferMut<T> { 17 + fn push(&mut self, value: T); 18 + fn clear(&mut self); 19 + fn as_slice(&self) -> &[T]; 20 + fn len(&self) -> usize; 21 + fn is_empty(&self) -> bool; 22 + } 23 + 24 + #[cfg(feature = "alloc")] 25 + impl<T> BufferMut<T> for alloc::vec::Vec<T> { 26 + fn push(&mut self, value: T) { 27 + self.push(value); 28 + } 29 + 30 + fn clear(&mut self) { 31 + self.clear(); 32 + } 33 + 34 + fn len(&self) -> usize { 35 + self.len() 36 + } 37 + 38 + fn is_empty(&self) -> bool { 39 + self.is_empty() 40 + } 41 + 42 + fn as_slice(&self) -> &[T] { 43 + self 44 + } 45 + } 46 + 47 + #[cfg(feature = "heapless")] 48 + impl<T> BufferMut<T> for heapless::Vec<T, crate::BLOCK_SIZE> { 49 + fn push(&mut self, value: T) { 50 + self.push(value).ok(); 51 + } 52 + 53 + fn clear(&mut self) { 54 + self.clear(); 55 + } 56 + 57 + fn as_slice(&self) -> &[T] { 58 + self 59 + } 60 + 61 + fn len(&self) -> usize { 62 + self.as_slice().len() 63 + } 64 + 65 + fn is_empty(&self) -> bool { 66 + self.is_empty() 67 + } 68 + }

History

10 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
feat: Embassy driver
1/1 success
expand
expand 0 comments
pull request successfully merged
1 commit
expand
feat: Embassy driver
1/1 success
expand
expand 0 comments
1 commit
expand
feat: Embassy driver
1/1 success
expand
expand 0 comments
1 commit
expand
feat: Embassy driver
1/1 failed
expand
expand 0 comments
1 commit
expand
feat: Embassy driver
1/1 success
expand
expand 0 comments
1 commit
expand
feat: Embassy driver
1/1 success
expand
expand 0 comments
1 commit
expand
feat: Embassy driver
1/1 failed
expand
expand 0 comments
1 commit
expand
feat: Embassy driver
expand 0 comments
1 commit
expand
feat: Embassy driver
expand 0 comments
1 commit
expand
feat: Embassy driver
expand 0 comments