1use embedded_hal::i2c::I2c;
10
11use crate::devices;
12
13const SINE_64_Q15: [i16; 64] = [
14 0, 3212, 6393, 9512, 12539, 15446, 18205, 20787, 23170, 25329, 27245, 28898, 30273, 31357,
15 32138, 32610, 32767, 32610, 32138, 31357, 30273, 28898, 27245, 25329, 23170, 20787, 18205,
16 15446, 12539, 9512, 6393, 3212, 0, -3212, -6393, -9512, -12539, -15446, -18205, -20787, -23170,
17 -25329, -27245, -28898, -30273, -31357, -32138, -32610, -32767, -32610, -32138, -31357, -30273,
18 -28898, -27245, -25329, -23170, -20787, -18205, -15446, -12539, -9512, -6393, -3212,
19];
20
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub enum SampleRate {
25 Rate8K,
27 Rate16K,
29 Rate24K,
31 Rate32K,
33 Rate44K1,
35 Rate48K,
37}
38
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
42pub enum SampleWidth {
43 Bits16,
45 Bits24,
47 Bits32,
49}
50
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum I2sMode {
55 Standard,
57 LeftJustified,
59}
60
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub struct I2sAudioFormat {
65 pub sample_rate: SampleRate,
67 pub sample_width: SampleWidth,
69 pub mode: I2sMode,
71 pub microphone_channels: u8,
73 pub speaker_channels: u8,
75}
76
77impl I2sAudioFormat {
78 pub const DEFAULT: Self = Self {
80 sample_rate: SampleRate::Rate16K,
81 sample_width: SampleWidth::Bits16,
82 mode: I2sMode::Standard,
83 microphone_channels: 2,
84 speaker_channels: 1,
85 };
86
87 pub const fn sample_rate_hz(self) -> u32 {
89 match self.sample_rate {
90 SampleRate::Rate8K => 8_000,
91 SampleRate::Rate16K => 16_000,
92 SampleRate::Rate24K => 24_000,
93 SampleRate::Rate32K => 32_000,
94 SampleRate::Rate44K1 => 44_100,
95 SampleRate::Rate48K => 48_000,
96 }
97 }
98}
99
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103pub struct MicrophoneConfig {
104 pub format: I2sAudioFormat,
106 pub gain_db: u8,
108}
109
110impl MicrophoneConfig {
111 pub const DEFAULT: Self = Self {
113 format: I2sAudioFormat::DEFAULT,
114 gain_db: 24,
115 };
116}
117
118#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[derive(Clone, Copy, Debug, Eq, PartialEq)]
121pub struct SpeakerConfig {
122 pub format: I2sAudioFormat,
124 pub enabled: bool,
126 pub volume: u8,
131}
132
133impl SpeakerConfig {
134 pub const DEFAULT: Self = Self {
136 format: I2sAudioFormat::DEFAULT,
137 enabled: true,
138 volume: 100,
139 };
140}
141
142pub trait AudioSource {
147 fn next_sample(&mut self) -> Option<i16>;
149}
150
151pub struct RawPcm<'a> {
153 samples: &'a [i16],
154 position: usize,
155 repeat: bool,
156}
157
158impl<'a> RawPcm<'a> {
159 pub const fn once(samples: &'a [i16]) -> Self {
161 Self {
162 samples,
163 position: 0,
164 repeat: false,
165 }
166 }
167
168 pub const fn repeating(samples: &'a [i16]) -> Self {
172 Self {
173 samples,
174 position: 0,
175 repeat: true,
176 }
177 }
178}
179
180impl AudioSource for RawPcm<'_> {
181 fn next_sample(&mut self) -> Option<i16> {
182 if self.samples.is_empty() {
183 return None;
184 }
185 if self.position >= self.samples.len() {
186 if self.repeat {
187 self.position = 0;
188 } else {
189 return None;
190 }
191 }
192 let sample = self.samples[self.position];
193 self.position += 1;
194 Some(sample)
195 }
196}
197
198#[cfg_attr(feature = "defmt", derive(defmt::Format))]
200#[derive(Clone, Copy, Debug, Eq, PartialEq)]
201pub enum WavError {
202 Truncated,
204 NotWave,
206 UnsupportedFormat,
208 MissingData,
210}
211
212pub struct WavPcm16<'a> {
219 data: &'a [u8],
220 cursor: usize,
221 end: usize,
222 channels: u16,
223 sample_rate_hz: u32,
224}
225
226impl<'a> WavPcm16<'a> {
227 pub fn new(wav: &'a [u8]) -> Result<Self, WavError> {
229 if wav.len() < 12 {
230 return Err(WavError::Truncated);
231 }
232 if &wav[0..4] != b"RIFF" || &wav[8..12] != b"WAVE" {
233 return Err(WavError::NotWave);
234 }
235
236 let mut offset = 12;
237 let mut channels = 0u16;
238 let mut sample_rate_hz = 0u32;
239 let mut bits_per_sample = 0u16;
240 let mut format_tag = 0u16;
241 let mut data_range = None;
242
243 while offset + 8 <= wav.len() {
244 let id = &wav[offset..offset + 4];
245 let size = read_le_u32(wav, offset + 4).ok_or(WavError::Truncated)? as usize;
246 let payload = offset + 8;
247 let next = payload.checked_add(size).ok_or(WavError::Truncated)?;
248 if next > wav.len() {
249 return Err(WavError::Truncated);
250 }
251
252 if id == b"fmt " {
253 if size < 16 {
254 return Err(WavError::UnsupportedFormat);
255 }
256 format_tag = read_le_u16(wav, payload).ok_or(WavError::Truncated)?;
257 channels = read_le_u16(wav, payload + 2).ok_or(WavError::Truncated)?;
258 sample_rate_hz = read_le_u32(wav, payload + 4).ok_or(WavError::Truncated)?;
259 bits_per_sample = read_le_u16(wav, payload + 14).ok_or(WavError::Truncated)?;
260 } else if id == b"data" {
261 data_range = Some((payload, next));
262 }
263
264 offset = next + (size & 1);
265 }
266
267 if format_tag != 1 || bits_per_sample != 16 || !(channels == 1 || channels == 2) {
268 return Err(WavError::UnsupportedFormat);
269 }
270 let (cursor, end) = data_range.ok_or(WavError::MissingData)?;
271 Ok(Self {
272 data: wav,
273 cursor,
274 end,
275 channels,
276 sample_rate_hz,
277 })
278 }
279
280 pub const fn sample_rate_hz(&self) -> u32 {
282 self.sample_rate_hz
283 }
284
285 pub const fn channels(&self) -> u16 {
287 self.channels
288 }
289}
290
291impl AudioSource for WavPcm16<'_> {
292 fn next_sample(&mut self) -> Option<i16> {
293 match self.channels {
294 1 => {
295 if self.cursor + 2 > self.end {
296 return None;
297 }
298 let sample = read_le_i16(self.data, self.cursor)?;
299 self.cursor += 2;
300 Some(sample)
301 }
302 2 => {
303 if self.cursor + 4 > self.end {
304 return None;
305 }
306 let left = i32::from(read_le_i16(self.data, self.cursor)?);
307 let right = i32::from(read_le_i16(self.data, self.cursor + 2)?);
308 self.cursor += 4;
309 Some(((left + right) / 2) as i16)
310 }
311 _ => None,
312 }
313 }
314}
315
316fn read_le_u16(data: &[u8], offset: usize) -> Option<u16> {
317 let bytes = data.get(offset..offset + 2)?;
318 Some(u16::from_le_bytes([bytes[0], bytes[1]]))
319}
320
321fn read_le_i16(data: &[u8], offset: usize) -> Option<i16> {
322 let bytes = data.get(offset..offset + 2)?;
323 Some(i16::from_le_bytes([bytes[0], bytes[1]]))
324}
325
326fn read_le_u32(data: &[u8], offset: usize) -> Option<u32> {
327 let bytes = data.get(offset..offset + 4)?;
328 Some(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
329}
330
331pub struct Tone {
333 phase: u32,
334 phase_step: u32,
335 remaining_samples: u32,
336 amplitude: i16,
337}
338
339impl Tone {
340 pub const fn new(
345 frequency_hz: u16,
346 duration_ms: u16,
347 sample_rate_hz: u32,
348 amplitude: i16,
349 ) -> Self {
350 let phase_step = match ((frequency_hz as u32) << 16).checked_div(sample_rate_hz) {
351 Some(value) => value,
352 None => 0,
353 };
354 let remaining_samples = (sample_rate_hz / 1000) * duration_ms as u32;
355
356 Self {
357 phase: 0,
358 phase_step,
359 remaining_samples,
360 amplitude,
361 }
362 }
363}
364
365impl AudioSource for Tone {
366 fn next_sample(&mut self) -> Option<i16> {
367 if self.remaining_samples == 0 {
368 return None;
369 }
370 self.remaining_samples -= 1;
371 let index = ((self.phase >> 10) & 0x3F) as usize;
372 self.phase = self.phase.wrapping_add(self.phase_step);
373 Some(((i32::from(SINE_64_Q15[index]) * i32::from(self.amplitude)) / 32767) as i16)
374 }
375}
376
377pub struct Es7210<I2C> {
379 i2c: I2C,
380 address: u8,
381}
382
383impl<I2C> Es7210<I2C> {
384 pub const fn new(i2c: I2C) -> Self {
386 Self {
387 i2c,
388 address: devices::i2c::ES7210_ADC,
389 }
390 }
391 pub fn release(self) -> I2C {
393 self.i2c
394 }
395}
396
397impl<I2C, Error> Es7210<I2C>
398where
399 I2C: I2c<Error = Error>,
400{
401 pub fn init(&mut self, config: MicrophoneConfig) -> Result<(), Error> {
403 self.write_register(0x00, 0xFF)?;
406 self.write_register(0x00, 0x32)?;
407 self.write_register(0x01, 0x30)?;
408 self.write_register(0x02, 0x10)?;
409 self.write_register(0x03, 0x20)?;
410 self.write_register(0x04, sample_width_code(config.format.sample_width))?;
411 self.write_register(0x22, config.gain_db.min(37))
412 }
413
414 pub fn set_gain(&mut self, gain_db: u8) -> Result<(), Error> {
416 self.write_register(0x22, gain_db.min(37))
417 }
418
419 pub fn read_register(&mut self, register: u8) -> Result<u8, Error> {
421 let mut value = [0u8];
422 self.i2c.write_read(self.address, &[register], &mut value)?;
423 Ok(value[0])
424 }
425
426 pub fn write_register(&mut self, register: u8, value: u8) -> Result<(), Error> {
428 self.i2c.write(self.address, &[register, value])
429 }
430}
431
432pub struct Aw88298<I2C> {
434 i2c: I2C,
435 address: u8,
436}
437
438impl<I2C> Aw88298<I2C> {
439 pub const fn new(i2c: I2C) -> Self {
441 Self {
442 i2c,
443 address: devices::i2c::AW88298_AMPLIFIER,
444 }
445 }
446 pub fn release(self) -> I2C {
448 self.i2c
449 }
450}
451
452impl<I2C, Error> Aw88298<I2C>
453where
454 I2C: I2c<Error = Error>,
455{
456 pub fn init(&mut self, config: SpeakerConfig) -> Result<(), Error> {
463 if config.enabled {
464 self.enable_core_s3(config)
465 } else {
466 self.set_enabled(false)
467 }
468 }
469
470 pub fn set_enabled(&mut self, enabled: bool) -> Result<(), Error> {
472 if enabled {
473 self.enable_core_s3(SpeakerConfig::DEFAULT)
474 } else {
475 self.write_register16(0x04, 0x4000)
476 }
477 }
478
479 pub fn set_volume(&mut self, volume: u8) -> Result<(), Error> {
481 self.write_register16(0x0C, u16::from(volume.min(100)))
482 }
483
484 fn enable_core_s3(&mut self, config: SpeakerConfig) -> Result<(), Error> {
485 let sample_rate_code = aw88298_sample_rate_code(config.format.sample_rate_hz());
486 self.write_register16(0x61, 0x0673)?;
487 self.write_register16(0x04, 0x4040)?;
488 self.write_register16(0x05, 0x0008)?;
489 self.write_register16(0x06, 0x14C0 | u16::from(sample_rate_code))?;
490 self.set_volume(config.volume)
491 }
492
493 pub fn read_register16(&mut self, register: u8) -> Result<u16, Error> {
495 let mut data = [0u8; 2];
496 self.i2c.write_read(self.address, &[register], &mut data)?;
497 Ok(u16::from_be_bytes(data))
498 }
499
500 pub fn write_register16(&mut self, register: u8, value: u16) -> Result<(), Error> {
502 let bytes = value.to_be_bytes();
503 self.i2c
504 .write(self.address, &[register, bytes[0], bytes[1]])
505 }
506}
507
508const fn sample_width_code(width: SampleWidth) -> u8 {
509 match width {
510 SampleWidth::Bits16 => 0x60,
511 SampleWidth::Bits24 => 0x00,
512 SampleWidth::Bits32 => 0x10,
513 }
514}
515
516const fn aw88298_sample_rate_code(sample_rate_hz: u32) -> u8 {
517 let rate = (sample_rate_hz + 1_102) / 2_205;
518 if rate <= 4 {
519 0
520 } else if rate <= 5 {
521 1
522 } else if rate <= 6 {
523 2
524 } else if rate <= 8 {
525 3
526 } else if rate <= 10 {
527 4
528 } else if rate <= 11 {
529 5
530 } else if rate <= 15 {
531 6
532 } else if rate <= 20 {
533 7
534 } else if rate <= 22 {
535 8
536 } else {
537 9
538 }
539}
540
541#[cfg(test)]
542mod tests {
543 use super::*;
544
545 #[test]
546 fn raw_pcm_once_stops_after_slice() {
547 let mut pcm = RawPcm::once(&[10, -20]);
548
549 assert_eq!(pcm.next_sample(), Some(10));
550 assert_eq!(pcm.next_sample(), Some(-20));
551 assert_eq!(pcm.next_sample(), None);
552 assert_eq!(pcm.next_sample(), None);
553 }
554
555 #[test]
556 fn raw_pcm_repeating_loops() {
557 let mut pcm = RawPcm::repeating(&[1, 2, 3]);
558
559 assert_eq!(pcm.next_sample(), Some(1));
560 assert_eq!(pcm.next_sample(), Some(2));
561 assert_eq!(pcm.next_sample(), Some(3));
562 assert_eq!(pcm.next_sample(), Some(1));
563 }
564
565 #[test]
566 fn empty_repeating_pcm_stops() {
567 let mut pcm = RawPcm::repeating(&[]);
568
569 assert_eq!(pcm.next_sample(), None);
570 }
571
572 #[test]
573 fn wav_pcm16_parses_mono_prompt() {
574 let mut wav = WavPcm16::new(MONO_WAV).expect("valid mono wav");
575
576 assert_eq!(wav.sample_rate_hz(), 16_000);
577 assert_eq!(wav.channels(), 1);
578 assert_eq!(wav.next_sample(), Some(1_000));
579 assert_eq!(wav.next_sample(), Some(-1_000));
580 assert_eq!(wav.next_sample(), None);
581 }
582
583 #[test]
584 fn wav_pcm16_downmixes_stereo() {
585 let mut wav = WavPcm16::new(STEREO_WAV).expect("valid stereo wav");
586
587 assert_eq!(wav.sample_rate_hz(), 16_000);
588 assert_eq!(wav.channels(), 2);
589 assert_eq!(wav.next_sample(), Some(0));
590 assert_eq!(wav.next_sample(), Some(0));
591 assert_eq!(wav.next_sample(), None);
592 }
593
594 #[test]
595 fn wav_pcm16_rejects_non_wave() {
596 assert!(matches!(
597 WavPcm16::new(b"not wave"),
598 Err(WavError::Truncated)
599 ));
600 }
601
602 #[test]
603 fn tone_yields_finite_nonzero_samples() {
604 let mut tone = Tone::new(440, 10, 16_000, 8_000);
605 let mut nonzero = false;
606 let mut count = 0;
607
608 while let Some(sample) = tone.next_sample() {
609 nonzero |= sample != 0;
610 count += 1;
611 }
612
613 assert!(nonzero);
614 assert_eq!(count, 160);
615 assert_eq!(tone.next_sample(), None);
616 }
617
618 #[test]
619 fn tone_with_zero_sample_rate_is_exhausted() {
620 let mut tone = Tone::new(440, 100, 0, 8_000);
621
622 assert_eq!(tone.next_sample(), None);
623 }
624
625 #[test]
626 fn aw88298_sample_rate_code_matches_m5_rate_buckets() {
627 assert_eq!(aw88298_sample_rate_code(8_000), 0);
628 assert_eq!(aw88298_sample_rate_code(16_000), 3);
629 assert_eq!(aw88298_sample_rate_code(44_100), 7);
630 assert_eq!(aw88298_sample_rate_code(48_000), 8);
631 }
632
633 const MONO_WAV: &[u8] = &[
634 b'R', b'I', b'F', b'F', 40, 0, 0, 0, b'W', b'A', b'V', b'E', b'f', b'm', b't', b' ', 16, 0,
635 0, 0, 1, 0, 1, 0, 0x80, 0x3E, 0, 0, 0x00, 0x7D, 0, 0, 2, 0, 16, 0, b'd', b'a', b't', b'a',
636 4, 0, 0, 0, 0xE8, 0x03, 0x18, 0xFC,
637 ];
638
639 const STEREO_WAV: &[u8] = &[
640 b'R', b'I', b'F', b'F', 44, 0, 0, 0, b'W', b'A', b'V', b'E', b'f', b'm', b't', b' ', 16, 0,
641 0, 0, 1, 0, 2, 0, 0x80, 0x3E, 0, 0, 0x00, 0xFA, 0, 0, 4, 0, 16, 0, b'd', b'a', b't', b'a',
642 8, 0, 0, 0, 0xE8, 0x03, 0x18, 0xFC, 0x18, 0xFC, 0xE8, 0x03,
643 ];
644}