1#![no_std]
7#![warn(missing_debug_implementations)]
8#![warn(missing_docs)]
9
10pub use vs1003_pac as pac;
11
12use embedded_hal::{delay::DelayNs, digital::OutputPin as _, spi::SpiDevice};
13use fugit::ExtU32;
14
15#[derive(Debug)]
17pub struct Peripherals<TSci, TSdi, TDreq, TRst> {
18 pub sci: TSci,
21 pub sdi: TSdi,
24 pub dreq: TDreq,
26 pub xrst: TRst,
28}
29
30impl<TSci, TSdi, TDreq, TRst> Vs1003Peripherals for Peripherals<TSci, TSdi, TDreq, TRst>
31where
32 TSci: embedded_hal::spi::SpiDevice,
33 TSdi: embedded_hal::spi::SpiDevice,
34 TDreq: embedded_hal::digital::InputPin,
35 TRst: embedded_hal::digital::OutputPin,
36{
37 type TSci = TSci;
38 type TSdi = TSdi;
39 type TDreq = TDreq;
40 type TRst = TRst;
41 type Error = Error<TSci::Error, TSdi::Error, TDreq::Error, TRst::Error>;
42
43 fn take(self) -> Self {
44 self
45 }
46}
47
48pub trait Vs1003Peripherals {
52 type TSci: embedded_hal::spi::SpiDevice;
54 type TSdi: embedded_hal::spi::SpiDevice;
56 type TDreq: embedded_hal::digital::InputPin;
58 type TRst: embedded_hal::digital::OutputPin;
60
61 type Error: core::fmt::Debug
63 + core::error::Error
64 + From<
65 Error<
66 <Self::TSci as embedded_hal::spi::ErrorType>::Error,
67 <Self::TSdi as embedded_hal::spi::ErrorType>::Error,
68 <Self::TDreq as embedded_hal::digital::ErrorType>::Error,
69 <Self::TRst as embedded_hal::digital::ErrorType>::Error,
70 >,
71 >;
72
73 fn take(self) -> Peripherals<Self::TSci, Self::TSdi, Self::TDreq, Self::TRst>;
75}
76
77#[derive(Debug, thiserror::Error)]
78#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
79pub enum Error<ESci, ESdi, EDreq, ERst> {
81 #[error("Failed to communicate over SCI")]
83 Sci(ESci),
84
85 #[error("Failed to communicate over SDI")]
87 Sdi(ESdi),
88
89 #[error("Failed to read DREQ signal")]
91 DreqRead(EDreq),
92
93 #[error("Failed to write xRST signal")]
95 RstWrite(ERst),
96
97 #[error("Device is busy (DREQ is low)")]
99 Busy,
100
101 #[error("Timeout of {}us exceeded", .0.ticks())]
103 Timeout(fugit::MicrosDurationU32),
104}
105impl<ESci, ESdi, EDreq, ERst> From<pac::Vs1003InterfaceError<ESci, EDreq>>
106 for Error<ESci, ESdi, EDreq, ERst>
107{
108 fn from(value: pac::Vs1003InterfaceError<ESci, EDreq>) -> Self {
109 match value {
110 pac::Vs1003InterfaceError::Spi(err) => Self::Sci(err),
111 pac::Vs1003InterfaceError::Dreq(err) => Self::DreqRead(err),
112 pac::Vs1003InterfaceError::Busy => Self::Busy,
113 }
114 }
115}
116
117#[derive(thiserror::Error)]
118#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
119pub struct ModeChangeError<T: Vs1003Peripherals> {
121 pub error: T::Error,
123 pub device: Vs1003<Errored, T>,
125}
126impl<T: Vs1003Peripherals> core::fmt::Debug for ModeChangeError<T> {
127 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
128 f.debug_tuple("ModeChangeError").field(&self.error).finish()
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
134#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
135#[repr(u8)]
136pub enum ClockMultiplier {
138 Times1_0 = 0,
140 Times1_5 = 1,
142 Times2_0 = 2,
144 Times2_5 = 3,
146 Times3_0 = 4,
148 Times3_5 = 5,
150 Times4_0 = 6,
152 Times4_5 = 7,
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
159#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
160#[repr(u8)]
161pub enum ClockBoost {
164 Plus0_0 = 0,
166 Plus0_5 = 1,
168 Plus1_0 = 2,
170 Plus1_5 = 3,
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
175#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
176pub enum RecordingInput {
178 LineIn,
180 Microphone,
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
185#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
186pub enum RecordingGain {
188 Auto,
190 Manual(core::num::NonZeroU16),
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
196pub enum RecordingFilter {
198 NoFilter,
200 HighPass,
204}
205
206#[derive(Debug)]
208#[non_exhaustive]
209pub struct NotInitialized {}
210
211#[derive(Debug)]
213#[non_exhaustive]
214pub struct Errored {}
215
216#[derive(Debug)]
218#[non_exhaustive]
219pub struct Initialized {
220 internal_clock: fugit::KilohertzU32,
222}
223
224#[derive(Debug)]
226#[non_exhaustive]
227pub struct AdpcmRecording {}
228
229#[derive(Debug)]
230#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
231pub struct Vs1003<State, T: Vs1003Peripherals> {
233 sci: pac::Vs1003<pac::Vs1003Interface<T::TSci, T::TDreq>>,
234 sdi: T::TSdi,
235 xrst: T::TRst,
236 state: State,
237}
238
239impl<T: Vs1003Peripherals> Vs1003<NotInitialized, T> {
240 pub fn new(peripherals: T) -> Self {
242 let Peripherals {
243 sci,
244 sdi,
245 dreq,
246 xrst,
247 } = peripherals.take();
248
249 Self {
250 sci: pac::Vs1003::new(pac::Vs1003Interface::new(sci, dreq)),
251 sdi,
252 xrst,
253 state: NotInitialized {},
254 }
255 }
256}
257
258impl<State, T: Vs1003Peripherals> Vs1003<State, T> {
259 pub fn reset_initialize(
278 mut self,
279 delay: &mut impl DelayNs,
280 xtali: fugit::KilohertzU32,
281 base_multiplier: ClockMultiplier,
282 wma_boost: ClockBoost,
283 ) -> Result<Vs1003<Initialized, T>, ModeChangeError<T>> {
284 let xtali_4k: u32 = xtali.to_kHz() / 4;
285 assert!(xtali_4k > 2_000, "Provided frequency is too low!");
286 let clock_input = xtali_4k - 2_000;
287 assert!(
288 clock_input < u16::MAX as u32,
289 "Provided frequency is too high!"
290 );
291 let clock_input = clock_input as u16;
292 let internal_clock = xtali
293 * match base_multiplier {
294 ClockMultiplier::Times1_0 => 2,
296 ClockMultiplier::Times1_5 => 3,
297 ClockMultiplier::Times2_0 => 4,
298 ClockMultiplier::Times2_5 => 5,
299 ClockMultiplier::Times3_0 => 6,
300 ClockMultiplier::Times3_5 => 7,
301 ClockMultiplier::Times4_0 => 8,
302 ClockMultiplier::Times4_5 => 9,
303 }
304 / 2;
305
306 let mut do_reset = move |dev: &mut Self| -> Result<(), T::Error> {
307 dev.xrst.set_low().map_err(Error::RstWrite)?;
308 delay.delay_us(100);
309 dev.xrst.set_high().map_err(Error::RstWrite)?;
310 delay.delay_ms(5);
311 dev.wait_for_dreq(delay, 10.millis())?;
315
316 dev.sci()
317 .clockf()
318 .modify(move |r| {
319 r.set_multiplier(base_multiplier as u8);
320 r.set_allowed_addition(wma_boost as u8);
321 r.set_input_frequency(clock_input);
322 })
323 .map_err(Error::from)?;
324
325 dev.wait_for_dreq(delay, 5.millis())?;
329 Ok(())
330 };
331
332 match do_reset(&mut self) {
333 Err(error) => Err(ModeChangeError {
334 error,
335 device: Vs1003 {
336 sci: self.sci,
337 sdi: self.sdi,
338 xrst: self.xrst,
339 state: Errored {},
340 },
341 }),
342 Ok(_) => Ok(Vs1003 {
343 sci: self.sci,
344 sdi: self.sdi,
345 xrst: self.xrst,
346 state: Initialized { internal_clock },
347 }),
348 }
349 }
350
351 pub fn is_busy(&mut self) -> Result<bool, T::Error> {
354 Ok(self.sci.is_busy().map_err(Error::DreqRead)?)
355 }
356
357 pub fn sci(&mut self) -> &mut pac::Vs1003<pac::Vs1003Interface<T::TSci, T::TDreq>> {
359 &mut self.sci
360 }
361
362 fn wait_for_dreq(
363 &mut self,
364 delay: &mut impl embedded_hal::delay::DelayNs,
365 max_delay: fugit::MicrosDurationU32,
366 ) -> Result<(), T::Error> {
367 const DELAY_STEP: u32 = 10;
368
369 let mut remaining_delay_us = max_delay.ticks();
370
371 while remaining_delay_us > 0 {
372 delay.delay_us(remaining_delay_us.min(DELAY_STEP));
373 if !self.is_busy()? {
374 return Ok(());
375 }
376 remaining_delay_us = remaining_delay_us.saturating_sub(DELAY_STEP);
377 }
378
379 Err(Error::Timeout(max_delay))?
380 }
381
382 fn change_state<NewState>(self, state: NewState) -> Vs1003<NewState, T> {
383 Vs1003 {
384 sci: self.sci,
385 sdi: self.sdi,
386 xrst: self.xrst,
387 state,
388 }
389 }
390}
391
392impl<T: Vs1003Peripherals> Vs1003<Initialized, T> {
393 pub fn begin_adpcm_recording(
410 mut self,
411 delay: &mut impl DelayNs,
412 sample_rate: fugit::HertzU32,
413 input: RecordingInput,
414 gain: RecordingGain,
415 filter: RecordingFilter,
416 ) -> Result<Vs1003<AdpcmRecording, T>, ModeChangeError<T>> {
417 let divider = self
418 .state
419 .internal_clock
420 .to_Hz()
421 .div_ceil(256 * sample_rate.to_Hz());
422 assert!(
423 divider >= 4,
424 "Requested sample rate is too high for provided clock"
425 );
426 let mut do_change = move |dev: &mut Self| -> Result<(), T::Error> {
427 dev.sci
429 .ai_ctrl(0)
430 .write(|r| r.set_value(divider as u16))
431 .map_err(Error::from)?;
432
433 dev.wait_for_dreq(delay, 500.micros())?;
434
435 dev.sci
437 .ai_ctrl(1)
438 .write(|r| {
439 r.set_value(match gain {
440 RecordingGain::Auto => 0,
441 RecordingGain::Manual(non_zero) => non_zero.get(),
442 })
443 })
444 .map_err(Error::from)?;
445
446 dev.wait_for_dreq(delay, 500.micros())?;
447
448 dev.sci
452 .mode()
453 .modify(|r| {
454 r.set_reset(true);
455 r.set_adpcm(true);
456 r.set_adpcm_hp(matches!(filter, RecordingFilter::HighPass));
457 r.set_adpcm_input(match input {
458 RecordingInput::LineIn => pac::AdpcmInput::LineIn,
459 RecordingInput::Microphone => pac::AdpcmInput::Microphone,
460 });
461 })
462 .map_err(Error::from)?;
463
464 dev.wait_for_dreq(delay, 10.millis())?;
465 Ok(())
466 };
467
468 match do_change(&mut self) {
469 Err(error) => Err(ModeChangeError {
470 error,
471 device: self.change_state(Errored {}),
472 }),
473 Ok(_) => Ok(self.change_state(AdpcmRecording {})),
474 }
475 }
476
477 pub fn send_data(&mut self, buffer: &[u8]) -> Result<usize, T::Error> {
482 if self.is_busy()? {
483 return Err(Error::Busy)?;
484 }
485
486 const CHUNK_SIZE: usize = 32;
488
489 let mut remaining = buffer;
490
491 while !remaining.is_empty() {
492 let (taken, leftover) = remaining.split_at(CHUNK_SIZE.min(remaining.len()));
493 remaining = leftover;
494
495 self.sdi.write(taken).map_err(Error::Sdi)?;
496
497 if self.is_busy()? {
499 break;
500 }
501 }
502
503 Ok(buffer.len() - remaining.len())
504 }
505
506 pub fn into_errored_state(self) -> Vs1003<Errored, T> {
509 self.change_state(Errored {})
510 }
511}
512
513impl<T: Vs1003Peripherals> Vs1003<AdpcmRecording, T> {
514 pub fn into_errored_state(self) -> Vs1003<Errored, T> {
517 self.change_state(Errored {})
518 }
519
520 pub fn get_ready_sample_count(&mut self) -> Result<usize, T::Error> {
525 self.sci
526 .hdat_1()
527 .read()
528 .map(|v| v.value() as usize)
529 .map_err(Error::from)
530 .map_err(Into::into)
531 }
532
533 pub fn read_samples(
548 &mut self,
549 delay: &mut impl DelayNs,
550 buffer: &mut [u16],
551 ) -> Result<usize, T::Error> {
552 let total_samples = self.get_ready_sample_count()?.min(buffer.len());
553 for sample in &mut buffer[0..total_samples] {
554 self.wait_for_dreq(delay, 100.micros())?;
555 *sample = self.sci.hdat_0().read().map_err(Error::from)?.value();
556 }
557
558 Ok(total_samples)
559 }
560
561 pub fn read_samples_bytes(
566 &mut self,
567 delay: &mut impl DelayNs,
568 buffer: &mut [u8],
569 ) -> Result<usize, T::Error> {
570 let total_samples = self.get_ready_sample_count()?.min(buffer.len() / 2);
571 for i in 0..total_samples {
572 self.wait_for_dreq(delay, 100.micros())?;
573 let sample = self.sci.hdat_0().read().map_err(Error::from)?.value();
574 let offset = i * 2;
575 buffer[offset..=offset + 1].copy_from_slice(&sample.to_be_bytes());
576 }
577
578 Ok(total_samples * 2)
579 }
580}