.tangled/workflows/test.yml
.tangled/workflows/test.yml
This file has not been changed.
+13
-2
Cargo.lock
+13
-2
Cargo.lock
···
42
42
"critical-section",
43
43
"embassy-sync",
44
44
"embassy-time",
45
+
"heapless 0.9.2",
45
46
"pollster",
46
47
]
47
48
···
56
57
"embedded-io-async",
57
58
"futures-core",
58
59
"futures-sink",
59
-
"heapless",
60
+
"heapless 0.8.0",
60
61
]
61
62
62
63
[[package]]
···
92
93
checksum = "80e2ee86063bd028a420a5fb5898c18c87a8898026da1d4c852af2c443d0a454"
93
94
dependencies = [
94
95
"embassy-executor-timer-queue",
95
-
"heapless",
96
+
"heapless 0.8.0",
96
97
]
97
98
98
99
[[package]]
···
161
162
version = "0.8.0"
162
163
source = "registry+https://github.com/rust-lang/crates.io-index"
163
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"
164
175
dependencies = [
165
176
"hash32",
166
177
"stable_deref_trait",
Cargo.toml
Cargo.toml
This file has not been changed.
README.md
README.md
This file has not been changed.
+6
embassy-strike-driver/Cargo.toml
+6
embassy-strike-driver/Cargo.toml
···
7
7
license.workspace = true
8
8
rust-version.workspace = true
9
9
10
+
[features]
11
+
default = []
12
+
alloc = []
13
+
heapless = ["dep:heapless"]
14
+
10
15
[dependencies]
11
16
embassy-time.workspace = true
12
17
embassy-sync.workspace = true
18
+
heapless = { version = "0.9.2", optional = true }
13
19
14
20
[dev-dependencies]
15
21
embassy-time = { workspace = true, features = ["mock-driver", "generic-queue-8"] }
+10
-52
embassy-strike-driver/src/lib.rs
+10
-52
embassy-strike-driver/src/lib.rs
···
2
2
//!
3
3
#![no_std]
4
4
5
+
#[cfg(feature = "alloc")]
6
+
extern crate alloc;
7
+
8
+
mod analysis;
9
+
pub mod traits;
10
+
5
11
use core::cell::Cell;
6
12
7
13
use embassy_sync::{
···
10
16
};
11
17
use embassy_time::{Duration, Instant, Ticker, Timer};
12
18
19
+
use crate::traits::{AdcSource, BufferMut, PwmSource, TimeSource};
20
+
13
21
pub const BLOCK_SIZE: usize = 512;
14
22
pub type ZeroCopyChannel<'device> = Channel<'device, NoopRawMutex, (i64, [u16; BLOCK_SIZE])>;
15
23
16
-
pub trait TimeSource {
17
-
fn timestamp(&self) -> i64;
18
-
fn get_source() -> Self;
19
-
}
20
-
21
-
pub trait AdcSource {
22
-
fn sample_average(&self, samples: &mut [u16]) -> impl Future<Output = u16>;
23
-
fn sample(&self, samples: &mut [u16]) -> impl Future<Output = ()>;
24
-
}
25
-
26
-
pub trait PwmSource {
27
-
fn set_duty(&mut self, duty: u16);
28
-
}
29
-
30
-
/// A Mutable Buffer trait
31
-
pub trait BufferMut<T> {
32
-
fn push(&mut self, value: T);
33
-
fn clear(&mut self);
34
-
fn as_slice(&self) -> &[T];
35
-
fn len(&self) -> usize;
36
-
fn is_empty(&self) -> bool;
37
-
}
38
-
39
24
#[derive(Debug)]
40
25
struct DetectorState {
41
26
max_duty: Cell<u8>,
···
185
170
{
186
171
peaks.clear();
187
172
188
-
let new_avg = analyse_buffer_by_stepped_windows(
173
+
let new_avg = analysis::analyse_buffer_by_stepped_windows(
189
174
self.config.blip_threshold.get(),
190
175
samples,
191
176
self.state.avg.get(),
···
268
253
}
269
254
}
270
255
271
-
fn analyse_buffer_by_stepped_windows<B: BufferMut<usize>>(
272
-
threshold: u16,
273
-
buf: &[u16],
274
-
average: u16,
275
-
peaks: &mut B,
276
-
) -> u16 {
277
-
const CHUNK_SIZE: usize = BLOCK_SIZE / 32;
278
-
const CHUNK_STEP: usize = CHUNK_SIZE / 2;
279
-
280
-
let mut total = 0u32;
281
-
let mut len = 0u32;
282
-
283
-
for (i, window) in buf.windows(CHUNK_SIZE).enumerate().step_by(CHUNK_STEP) {
284
-
let window_total = window.iter().copied().sum::<u16>();
285
-
let window_avg = window_total / CHUNK_SIZE as u16;
286
-
let diff = average.saturating_sub(window_avg);
287
-
288
-
if diff > threshold {
289
-
peaks.push(i);
290
-
} else {
291
-
total += window_total as u32;
292
-
len += CHUNK_SIZE as u32;
293
-
}
294
-
}
295
-
296
-
(total / len) as u16
297
-
}
298
-
299
256
#[cfg(test)]
300
257
mod tests {
301
258
use core::future::poll_fn;
···
346
303
}
347
304
}
348
305
306
+
#[cfg(not(feature = "alloc"))]
349
307
impl BufferMut<usize> for alloc::vec::Vec<usize> {
350
308
fn push(&mut self, value: usize) {
351
309
self.push(value);
+29
embassy-strike-driver/src/analysis.rs
+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
+
}
+68
embassy-strike-driver/src/traits.rs
+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
1 commit
expand
collapse
feat: Embassy driver
1/1 success
expand
collapse
expand 0 comments
pull request successfully merged
1 commit
expand
collapse
feat: Embassy driver
1/1 success
expand
collapse
expand 0 comments
1 commit
expand
collapse
feat: Embassy driver
1/1 success
expand
collapse
expand 0 comments
1 commit
expand
collapse
feat: Embassy driver
1/1 failed
expand
collapse
expand 0 comments
1 commit
expand
collapse
feat: Embassy driver
1/1 success
expand
collapse
expand 0 comments
1 commit
expand
collapse
feat: Embassy driver
1/1 success
expand
collapse
expand 0 comments
1 commit
expand
collapse
feat: Embassy driver