capsules_extra/
adc_microphone.rs1use core::cell::Cell;
6
7use kernel::hil::adc;
8use kernel::hil::gpio;
9use kernel::hil::sensors::{SoundPressure, SoundPressureClient};
10use kernel::utilities::cells::{OptionalCell, TakeCell};
11use kernel::utilities::math;
12use kernel::ErrorCode;
13
14#[derive(Copy, Clone, PartialEq)]
15enum State {
16 Idle,
17 ReadingSPL,
18}
19
20pub struct AdcMicrophone<'a, P: gpio::Pin> {
21 adc: &'a dyn adc::AdcChannel<'a>,
22 enable_pin: Option<&'a P>,
23 spl_client: OptionalCell<&'a dyn SoundPressureClient>,
24 spl_buffer: TakeCell<'a, [u16]>,
25 spl_pos: Cell<usize>,
26 state: Cell<State>,
27}
28
29impl<'a, P: gpio::Pin> AdcMicrophone<'a, P> {
30 pub fn new(
31 adc: &'a dyn adc::AdcChannel<'a>,
32 enable_pin: Option<&'a P>,
33 spl_buffer: &'a mut [u16],
34 ) -> AdcMicrophone<'a, P> {
35 enable_pin.map(|pin| pin.make_output());
36 AdcMicrophone {
37 adc,
38 enable_pin,
39 spl_client: OptionalCell::empty(),
40 spl_buffer: TakeCell::new(spl_buffer),
41 spl_pos: Cell::new(0),
42 state: Cell::new(State::Idle),
43 }
44 }
45
46 fn compute_spl(&self) -> u8 {
47 let max = self.spl_buffer.map_or(0, |buffer| {
48 let avg = (buffer.iter().fold(0usize, |a, v| a + *v as usize) / buffer.len()) as u16;
49 let max = buffer
50 .iter()
51 .map(|v| if *v > avg { v - avg } else { 0 })
52 .fold(0, |a, v| if a > v { a } else { v });
53 let mut conv = (max as f32) / (((1 << 15) - 1) as f32) * 9_f32;
54 conv = 20f32 * math::log10(conv / 0.00002f32);
55 conv as u8
56 });
57 max
58 }
59}
60
61impl<'a, P: gpio::Pin> SoundPressure<'a> for AdcMicrophone<'a, P> {
62 fn read_sound_pressure(&self) -> Result<(), ErrorCode> {
63 if self.state.get() == State::Idle {
64 self.state.set(State::ReadingSPL);
66 self.spl_pos.set(0);
67 let _ = self.adc.sample();
68 Ok(())
69 } else {
70 Err(ErrorCode::BUSY)
71 }
72 }
73
74 fn set_client(&self, client: &'a dyn SoundPressureClient) {
75 self.spl_client.set(client);
76 }
77
78 fn enable(&self) -> Result<(), ErrorCode> {
79 self.enable_pin.map(|pin| pin.set());
80 Ok(())
81 }
82
83 fn disable(&self) -> Result<(), ErrorCode> {
84 self.enable_pin.map(|pin| pin.clear());
85 Ok(())
86 }
87}
88
89impl<P: gpio::Pin> adc::Client for AdcMicrophone<'_, P> {
90 fn sample_ready(&self, sample: u16) {
91 if self.state.get() == State::ReadingSPL {
92 if self.spl_buffer.map_or(false, |buffer| {
93 if self.spl_pos.get() < buffer.len() {
94 buffer[self.spl_pos.get()] = sample;
95 self.spl_pos.set(self.spl_pos.get() + 1);
96 }
97 if self.spl_pos.get() < buffer.len() {
98 let _ = self.adc.sample();
99 false
100 } else {
101 self.state.set(State::Idle);
102 true
103 }
104 }) {
105 let spl = self.compute_spl();
107 self.spl_client.map(|client| client.callback(Ok(()), spl));
108 }
109 }
110 }
111}