1#[cfg(feature = "async")]
2use alloc::boxed::Box;
3use core::slice;
4#[cfg(not(feature = "fugit"))]
5use core::time::Duration;
6
7#[cfg(not(feature = "async"))]
8use embedded_hal::blocking::spi;
9use embedded_hal::{digital::v2::OutputPin, timer::CountDown};
10#[cfg(feature = "fugit")]
11use fugit::NanosDurationU32 as Duration;
12
13use crate::sd::{
14 command::{AppCommand, Command},
15 response::{self, Response},
16};
17
18use crate::bus;
19
20#[derive(Debug)]
21pub enum Error<SPI, CS> {
22 SPI(SPI),
23 CS(CS),
24}
25
26pub type BUSError<SPI, CS> = bus::Error<Error<SPI, CS>>;
27
28#[cfg_attr(feature = "async", async_trait::async_trait)]
29#[cfg_attr(not(feature = "async"), deasync::deasync)]
30pub trait Transfer {
31 type Error;
32 async fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error>;
33}
34
35#[cfg(not(feature = "async"))]
36impl<E, T: spi::Transfer<u8, Error = E>> Transfer for T {
37 type Error = E;
38
39 fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
40 rx.copy_from_slice(tx);
41 self.transfer(rx).map(|_| ())
42 }
43}
44
45pub struct Bus<SPI, CS, C> {
46 spi: SPI,
47 cs: CS,
48 pub(crate) countdown: C,
49}
50
51impl<E, SPI, CS, C> Bus<SPI, CS, C>
52where
53 CS: OutputPin<Error = E>,
54 C: CountDown<Time = Duration>,
55{
56 pub fn new(spi: SPI, cs: CS, countdown: C) -> Self {
57 Self { spi, cs, countdown }
58 }
59
60 pub fn spi<R>(&mut self, f: impl Fn(&mut SPI) -> R) -> R {
61 f(&mut self.spi)
62 }
63
64 pub(crate) fn select<T>(&mut self) -> Result<(), BUSError<T, E>> {
65 self.cs.set_low().map_err(|e| BUSError::BUS(Error::CS(e)))
66 }
67
68 pub(crate) fn deselect<T>(&mut self) -> Result<(), BUSError<T, E>> {
69 self.cs.set_high().map_err(|e| BUSError::BUS(Error::CS(e)))
70 }
71}
72
73#[cfg_attr(not(feature = "async"), deasync::deasync)]
74impl<E, F, SPI, CS, C> Bus<SPI, CS, C>
75where
76 SPI: Transfer<Error = E>,
77 CS: OutputPin<Error = F>,
78 C: CountDown<Time = Duration>,
79{
80 pub(crate) async fn tx(&mut self, bytes: &[u8]) -> Result<(), BUSError<E, F>> {
81 self.spi.transfer(bytes, &mut []).await.map_err(|e| BUSError::BUS(Error::SPI(e)))
82 }
83
84 pub(crate) async fn rx(&mut self, buffer: &mut [u8]) -> Result<(), BUSError<E, F>> {
85 self.spi.transfer(&[], buffer).await.map_err(|e| BUSError::BUS(Error::SPI(e)))
86 }
87
88 pub(crate) async fn wait(&mut self, timeout: Duration) -> Result<(), BUSError<E, F>> {
89 self.countdown.start(timeout);
90 let mut byte = 0u8;
91 while byte != 0xFFu8 {
92 if self.countdown.wait().is_ok() {
93 return Err(BUSError::Timeout);
94 }
95 self.rx(slice::from_mut(&mut byte)).await?;
96 }
97 Ok(())
98 }
99
100 pub(crate) async fn send_command(&mut self, cmd: Command) -> Result<Response, BUSError<E, F>> {
101 let bytes: [u8; 6] = cmd.into();
102 trace!("Send CMD {:?} bytes {:X?}", cmd, &bytes);
103 self.tx(&bytes[..]).await?;
104
105 if cmd == Command::StopTransmission {
106 self.rx(&mut [0u8]).await?; }
108
109 let mut r1 = response::R1::default();
111 for _ in 0..=8 {
112 self.rx(slice::from_mut(&mut r1.0)).await?;
113 if r1.valid() {
114 break;
115 }
116 }
117 if !r1.valid() {
118 return Err(BUSError::NoResponse);
119 }
120
121 if let Some(e) = r1.error() {
122 return Err(BUSError::Command(e));
123 }
124 let mut response = Response { r1, ..Default::default() };
125
126 let size = cmd.expected_response_ex_size();
127 if size > 0 {
128 let mut buffer = [0u8; 4];
129 self.rx(&mut buffer[4 - size..]).await?;
130 response.ex = u32::from_be_bytes(buffer);
131 }
132 Ok(response)
133 }
134
135 pub(crate) async fn send_app_command(
136 &mut self,
137 cmd: AppCommand,
138 ) -> Result<Response, BUSError<E, F>> {
139 self.send_command(Command::AppCommand(0)).await?;
140 self.send_command(Command::App(cmd)).await
141 }
142}
143
144impl<E, F, SPI, CS, C> bus::Bus for Bus<SPI, CS, C>
145where
146 SPI: Transfer<Error = E>,
147 CS: OutputPin<Error = F>,
148 C: CountDown<Time = Duration>,
149{
150 type Error = Error<E, F>;
151
152 fn before(&mut self) -> Result<(), BUSError<E, F>> {
153 Ok(())
154 }
155
156 fn after(&mut self) -> Result<(), BUSError<E, F>> {
157 self.deselect()
158 }
159}
160
161pub(crate) fn millis(millis: u32) -> Duration {
162 match () {
163 #[cfg(not(feature = "fugit"))]
164 () => Duration::from_millis(millis as u64),
165 #[cfg(feature = "fugit")]
166 () => Duration::millis(millis),
167 }
168}