1use core::ops::{Deref, DerefMut};
2use embedded_time::duration::Extensions;
3
4use crate::traits::wg::timer::CountDown;
5use crate::{
6 drivers::{pins, timer, timer::Elapsed, Pin},
7 peripherals::{ctimer, dma::Dma},
8 typestates::{
9 init_state,
10 pin::{function, gpio::direction, state, PinId},
11 ClocksSupportTouchToken,
12 },
13};
14
15#[derive(Copy, Clone)]
17pub enum TouchSensorChannel {
18 Channel1 = 3,
19 Channel2 = 4,
20 Channel3 = 5,
21}
22
23pub struct ButtonPins<P1: PinId, P2: PinId, P3: PinId>(
24 pub Pin<P1, state::Analog<direction::Input>>,
25 pub Pin<P2, state::Analog<direction::Input>>,
26 pub Pin<P3, state::Analog<direction::Input>>,
27);
28
29type Adc = crate::peripherals::adc::Adc<init_state::Enabled>;
30
31pub struct TouchSensor<
32 P1: PinId,
33 P2: PinId,
34 P3: PinId,
35 > {
37 threshold: [u32; 3],
38 confidence: u32,
39 adc: Adc,
40 adc_timer: ctimer::Ctimer1<init_state::Enabled>,
41 sample_timer: ctimer::Ctimer2<init_state::Enabled>,
42 _buttons: ButtonPins<P1, P2, P3>,
43 }
45
46const RESULTS_LEN: usize = 128; const RESULTS_LEAD_SIZE: usize = 3; const AVERAGES: usize = 16;
53static mut RESULTS: [u32; RESULTS_LEN] = [0u32; RESULTS_LEN];
54
55const CHARGE_PERIOD_US: u32 = 400;
57
58impl<P1, P2, P3> Deref for TouchSensor<P1, P2, P3>
59where
60 P1: PinId,
61 P2: PinId,
62 P3: PinId,
63{
64 type Target = Adc;
65 fn deref(&self) -> &Self::Target {
66 &self.adc
67 }
68}
69
70impl<P1, P2, P3> DerefMut for TouchSensor<P1, P2, P3>
71where
72 P1: PinId,
73 P2: PinId,
74 P3: PinId,
75{
76 fn deref_mut(&mut self) -> &mut Self::Target {
77 &mut self.adc
78 }
79}
80
81impl<P1, P2, P3> TouchSensor<P1, P2, P3>
82where
83 P1: PinId,
84 P2: PinId,
85 P3: PinId,
86{
87 pub fn new(
90 threshold: [u32; 3],
91 confidence: u32,
92 adc: Adc,
93 adc_timer: ctimer::Ctimer1<init_state::Enabled>,
94 sample_timer: ctimer::Ctimer2<init_state::Enabled>,
95 _charge_pin: Pin<
96 pins::Pio1_16,
97 state::Special<function::MATCH_OUTPUT3<ctimer::Ctimer1<init_state::Enabled>>>,
98 >,
99 buttons: ButtonPins<P1, P2, P3>,
100 ) -> Self {
101 adc_timer.mcr.write(|w| {
104 w.mr3i()
105 .set_bit() .mr3r()
107 .set_bit() .mr3s()
109 .clear_bit() });
111
112 adc_timer.emr.write(|w| {
113 w.emc3().toggle() });
115
116 adc_timer.mr[3].write(|w| unsafe { w.bits(CHARGE_PERIOD_US) });
118
119 adc_timer.ir.write(|w| w.mr3int().set_bit());
121
122 sample_timer.mcr.write(|w| unsafe { w.bits(0) });
125 sample_timer.emr.write(|w| unsafe { w.bits(0) });
126 sample_timer.ir.modify(|r, w| unsafe { w.bits(r.bits()) });
127
128 adc.tctrl[6].write(|w| unsafe {
130 w.hten()
131 .set_bit()
132 .fifo_sel_a()
133 .fifo_sel_a_0()
134 .fifo_sel_b()
135 .fifo_sel_b_0()
136 .tcmd()
137 .bits(3) .tpri()
139 .bits(2)
140 });
141
142 adc.cmdl3.write(|w| unsafe {
143 w.adch()
144 .bits(buttons.0.state.channel)
145 .ctype()
146 .ctype_0() .mode()
148 .mode_0() });
150
151 adc.cmdh3.write(|w| unsafe {
152 w.avgs()
153 .avgs_6() .cmpen()
155 .bits(0b00) .loop_()
157 .bits(0) .next()
159 .bits(4) .wait_trig()
161 .set_bit() });
163
164 adc.cmdl4.write(|w| unsafe {
165 w.adch()
166 .bits(buttons.1.state.channel)
167 .ctype()
168 .ctype_0()
169 .mode()
170 .mode_0()
171 });
172 adc.cmdh4.write(|w| unsafe {
173 w.avgs()
174 .avgs_6()
175 .cmpen()
176 .bits(0b00)
177 .loop_()
178 .bits(0)
179 .next()
180 .bits(5) .wait_trig()
182 .set_bit()
183 });
184
185 adc.cmdl5.write(|w| unsafe {
186 w.adch()
187 .bits(buttons.2.state.channel)
188 .ctype()
189 .ctype_0()
190 .mode()
191 .mode_0()
192 });
193 adc.cmdh5.write(|w| unsafe {
194 w.avgs()
195 .avgs_6()
196 .loop_()
197 .bits(0)
198 .next()
199 .bits(3) .wait_trig()
201 .set_bit()
202 });
203
204 Self {
205 adc,
206 adc_timer,
207 sample_timer,
208 _buttons: buttons,
209 threshold,
210 confidence,
211 }
213 }
214}
215
216impl<P1, P2, P3> TouchSensor<P1, P2, P3>
217where
218 P1: PinId,
219 P2: PinId,
220 P3: PinId,
221{
222 pub fn enabled(
224 mut self,
225 dma: &mut Dma<init_state::Enabled>,
226 _token: ClocksSupportTouchToken,
227 ) -> Self {
229 dma.configure_adc(&mut self.adc, &mut self.sample_timer, unsafe {
230 &mut RESULTS
231 });
232
233 self.adc_timer
235 .tcr
236 .write(|w| w.crst().clear_bit().cen().set_bit());
237
238 self.sample_timer
239 .tcr
240 .write(|w| w.crst().clear_bit().cen().set_bit());
241
242 self
243 }
244}
245
246pub struct TouchResult {
247 pub is_active: bool,
248 pub at: usize,
249}
250
251#[derive(Copy, Clone, Debug, PartialEq)]
252pub enum Edge {
253 Rising,
254 Falling,
255}
256
257#[derive(Copy, Clone, Debug, PartialEq)]
258pub enum Compare {
259 AboveThreshold,
260 BelowThreshold,
261}
262
263impl<P1, P2, P3> TouchSensor<P1, P2, P3>
265where
266 P1: PinId,
267 P2: PinId,
268 P3: PinId,
269{
270 pub fn count(&self, bufsel: u8) -> u32 {
273 let results = unsafe { &RESULTS };
274 let mut count = 0u32;
275
276 let starting_point = self.get_starting_point();
277
278 for i in 0..(RESULTS_LEN - RESULTS_LEAD_SIZE) {
279 let src = ((results[(starting_point + i) % RESULTS_LEN] & (0xf << 24)) >> 24) as u8;
280
281 if src == bufsel {
282 count += 1;
283 }
284 }
285 count
286 }
287
288 pub(crate) fn get_results<'a>(&self) -> &'a mut [u32] {
290 unsafe { &mut RESULTS }
291 }
292
293 pub fn reset_results(&self, channel: TouchSensorChannel, offset: i32) {
296 let results = unsafe { &mut RESULTS };
297 for item in results {
300 if (*item & (0xf << 24)) == ((channel as u32) << 24) {
301 *item = (*item & (!0xffff))
302 | (self.threshold[(channel as usize) - 3] as i32 + offset) as u32;
303 }
304 }
305 }
325
326 fn get_starting_point(&self) -> usize {
328 let sync_time = self.sample_timer.tc.read().bits();
329
330 if sync_time < 1192 {
332 RESULTS_LEAD_SIZE
333 } else {
334 (((sync_time - 1192) / 802) as usize) + RESULTS_LEN + 1
335 }
336 }
337
338 fn measure_buffer(&self, bufsel: u8, filtered: &mut [u32; 40 - AVERAGES]) {
340 let results = unsafe { &RESULTS };
341 let mut buf = [0u32; 40];
342 let mut buf_i = 0;
343
344 let starting_point = self.get_starting_point();
345
346 for i in 0..(RESULTS_LEN - RESULTS_LEAD_SIZE) {
347 let res = results[(starting_point + i) % RESULTS_LEN];
348 let src = ((res & (0xf << 24)) >> 24) as u8;
349
350 if src == bufsel {
351 buf[buf_i] = res & 0xffff;
352 buf_i += 1;
353 if buf_i == buf.len() {
354 break;
355 }
356 }
357 }
358
359 for i in 0..(40 - AVERAGES) {
361 let mut sum = 0;
362 for j in 0..AVERAGES {
363 let samp = buf[i + j];
364 sum += samp;
365 }
366 filtered[i] = sum / (AVERAGES as u32);
367 }
368 }
369
370 pub fn get_state(&self, channel: TouchSensorChannel, ctype: Compare) -> TouchResult {
372 let mut filtered = [0u32; 40 - AVERAGES];
373 let bufsel = channel as u8;
374 self.measure_buffer(bufsel, &mut filtered);
375
376 if bufsel == 5 {
377 }
380
381 let mut streak = 0u32;
382
383 match ctype {
384 Compare::AboveThreshold =>
385 {
386 #[allow(clippy::needless_range_loop)]
387 for i in 0..(40 - AVERAGES) {
388 if filtered[i] > self.threshold[(5 - bufsel) as usize] {
389 streak += 1;
390 if streak > self.confidence {
391 return TouchResult {
392 is_active: true,
393 at: i,
394 };
395 }
396 }
397 }
398 }
399 Compare::BelowThreshold =>
400 {
401 #[allow(clippy::needless_range_loop)]
402 for i in 0..(40 - AVERAGES) {
403 if filtered[i] < self.threshold[(5 - bufsel) as usize] {
404 streak += 1;
405 if streak > self.confidence {
406 return TouchResult {
407 is_active: true,
408 at: i,
409 };
410 }
411 }
412 }
413 }
414 }
415 TouchResult {
416 is_active: false,
417 at: 0,
418 }
419 }
420
421 pub fn has_edge(&self, channel: TouchSensorChannel, edge_type: Edge) -> bool {
423 let low = self.get_state(channel, Compare::BelowThreshold);
424 let high = self.get_state(channel, Compare::AboveThreshold);
425
426 if high.is_active && low.is_active {
427 match edge_type {
428 Edge::Rising => {
429 return low.at < high.at;
430 }
431 Edge::Falling => {
432 return high.at < low.at;
433 }
434 }
435 }
436 false
437 }
438}
439
440pub fn profile_touch_sensing(
442 touch_sensor: &mut TouchSensor<impl PinId, impl PinId, impl PinId>,
443 delay_timer: &mut timer::Timer<impl ctimer::Ctimer<init_state::Enabled>>,
444 copy: &mut [u32],
445 times: &mut [u32],
446) {
447 let start = delay_timer.elapsed().0;
448 let results = touch_sensor.get_results();
449
450 delay_timer.start(300_000.microseconds());
451
452 loop {
453 let mut has_zero = false;
454 for i in 0..125 {
455 if results[i] != 0 {
456 if times[i] == 0 {
457 times[i] = delay_timer.elapsed().0 - start;
458 copy[i] = results[i];
459 }
460 } else {
461 has_zero = true;
462 }
463 }
464 if !has_zero {
465 break;
466 }
467 }
468}