use consts::NCR;
use core::mem;
use crc::{Crc, Crc16, Crc7};
use drone_core::drv::{Driver, Resource};
use drone_core::thr::prelude::*;
use errors::{CmdError, DmaError, R1Error, SpiInitError};
use futures::prelude::*;
use sd_spi::{SdSpi, SdSpiRes};
use tokens::{
Cond, Csd, Ocr, ReadResponse, Status, WriteResponse, BLOCK_START,
BLOCK_START_MULTI_WRITE, R1, STOP_TRAN,
};
const STARTUP_CYCLES: usize = 10;
const INIT_TIMEOUT: usize = 100;
static mut RX_FORGET: u8 = 0;
static TX_IDLE: u8 = 0xFF;
#[derive(Driver)]
#[driver(forward)]
pub struct SdSpiSessCore<T: SdSpiSessResCore>(T);
pub trait SdSpiSessResCore: Resource<Source = Self> + Driver {
type SdRes: SdSpiRes;
type SpiInt: ThrToken<Ltt>;
fn sd(&self) -> &SdSpi<Self::SdRes>;
fn sd_mut(&mut self) -> &mut SdSpi<Self::SdRes>;
fn spi_open(&self);
fn spi_close(&self);
unsafe fn dma_exchange<'sess>(
&'sess mut self,
rx_ptr: *mut u8,
rx_inc: bool,
rx_len: usize,
tx_ptr: *const u8,
tx_inc: bool,
tx_len: usize,
) -> Box<Future<Item = (), Error = DmaError> + 'sess>;
fn wait_byte<'sess, R, F>(
&'sess mut self,
first_byte: u8,
max_skip: usize,
f: F,
) -> Box<Future<Item = R, Error = CmdError> + 'sess>
where
R: Send + 'static,
F: FnMut(u8) -> Option<R> + Send + 'static;
fn send_byte(&mut self, value: u8);
fn startup_delay(&mut self) -> Box<Future<Item = (), Error = !>>;
}
impl<T: SdSpiSessResCore> SdSpiSessCore<T> {
#[inline(always)]
pub fn startup_wait(&mut self) -> Box<Future<Item = (), Error = !>> {
self.0.startup_delay()
}
pub fn init<'sess>(
&'sess mut self,
voltage: Ocr,
buf: &'sess mut [u8],
) -> impl Future<Item = Ocr, Error = SpiInitError> + 'sess {
async(static move || {
self.0.spi_open();
await!(self.startup_cycles())?;
self.0.sd().slave_select();
await!(self.wait_until_ready(INIT_TIMEOUT))?;
let r1 = await!(self.go_idle_state(buf))?;
if !r1.in_idle_state() {
return Err(SpiInitError::NotIdle);
}
await!(self.wait_until_ready(INIT_TIMEOUT))?;
match await!(self.send_if_cond(0b0001, 0xAA, buf)) {
Ok(cond) => {
if cond.is_err() {
return Err(SpiInitError::CondMismatch);
}
await!(self.wait_until_ready(INIT_TIMEOUT))?;
let (_r1, ocr) = await!(self.read_ocr(buf))?;
if !ocr.supports(voltage) {
return Err(SpiInitError::UnsupportedVoltage);
}
await!(self.wait_until_ready(INIT_TIMEOUT))?;
await!(self.crc_on_off(true, buf))?;
await!(self.wait_until_ready(INIT_TIMEOUT))?;
while await!(self.sd_send_op_cond(true, buf))?.in_idle_state() {
await!(self.wait_until_ready(INIT_TIMEOUT))?;
}
await!(self.wait_until_ready(INIT_TIMEOUT))?;
let (_r1, ocr) = await!(self.read_ocr(buf))?;
self.end();
Ok(ocr)
}
Err(CmdError::R1(R1Error::Illegal)) => {
await!(self.wait_until_ready(INIT_TIMEOUT))?;
let (_r1, ocr) = await!(self.read_ocr(buf))?;
if !ocr.supports(voltage) {
return Err(SpiInitError::UnsupportedVoltage);
}
await!(self.wait_until_ready(INIT_TIMEOUT))?;
await!(self.crc_on_off(true, buf))?;
await!(self.wait_until_ready(INIT_TIMEOUT))?;
while await!(self.sd_send_op_cond(false, buf))?.in_idle_state() {
await!(self.wait_until_ready(INIT_TIMEOUT))?;
}
self.end();
Ok(ocr)
}
Err(err) => Err(err)?,
}
})
}
pub fn begin(&self) {
self.0.spi_open();
self.0.sd().slave_select();
}
pub fn end(&self) {
self.0.spi_close();
self.0.sd().slave_unselect();
}
pub fn go_idle_state<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
) -> impl Future<Item = R1, Error = CmdError> + 'sess {
async(static move || {
await!(self.send_cmd(0, 0x0000_0000, buf))?;
Ok(await!(self.wait_r1())?)
})
}
pub fn send_if_cond<'sess>(
&'sess mut self,
voltage: u32,
pattern: u32,
buf: &'sess mut [u8],
) -> impl Future<Item = Result<(R1, Cond), (R1, Cond)>, Error = CmdError> + 'sess
{
async(static move || {
await!(self.send_cmd(8, (voltage << 8) | pattern, buf))?;
let r1 = await!(self.wait_r1())?;
r1.errck(true)?;
await!(self.recv_bytes(&mut buf[..4]))?;
let cond = Cond::from_buf(buf);
if cond.voltage_accepted() == voltage && cond.check_pattern() == pattern {
Ok(Ok((r1, cond)))
} else {
Ok(Err((r1, cond)))
}
})
}
pub fn send_csd<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
timeout: usize,
) -> impl Future<Item = (R1, Csd), Error = CmdError> + 'sess {
async(static move || {
await!(self.wait_until_ready(timeout))?;
await!(self.send_cmd(9, 0x0000_0000, buf))?;
let r1 = await!(self.wait_r1())?;
r1.errck(true)?;
await!(self.wait_read_response(timeout))?;
await!(self.recv_bytes(&mut buf[..16 + 2]))?;
let (data, crc) = buf.split_at(16);
self.data_crc_verify(data, crc)?;
Ok((r1, Csd::from_buf(buf)))
})
}
pub fn send_status<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
) -> impl Future<Item = (R1, Status), Error = CmdError> + 'sess {
async(static move || {
await!(self.send_cmd(13, 0x0000_0000, buf))?;
Ok(await!(self.wait_r2())?)
})
}
pub fn read_ocr<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
) -> impl Future<Item = (R1, Ocr), Error = CmdError> + 'sess {
async(static move || {
await!(self.send_cmd(58, 0x0000_0000, buf))?;
let r1 = await!(self.wait_r1())?;
r1.errck(true)?;
await!(self.recv_bytes(&mut buf[..4]))?;
Ok((r1, Ocr::from_buf(buf)))
})
}
pub fn sd_send_op_cond<'sess>(
&'sess mut self,
hcs: bool,
buf: &'sess mut [u8],
) -> impl Future<Item = R1, Error = CmdError> + 'sess {
async(static move || {
await!(self.send_app_cmd(41, (hcs as u32) << 30, buf))?;
Ok(await!(self.wait_r1())?)
})
}
pub fn set_blocklen<'sess>(
&'sess mut self,
length: u32,
buf: &'sess mut [u8],
) -> impl Future<Item = R1, Error = CmdError> + 'sess {
async(static move || {
await!(self.send_cmd(16, length, buf))?;
Ok(await!(self.wait_r1())?)
})
}
pub fn crc_on_off<'sess>(
&'sess mut self,
on: bool,
buf: &'sess mut [u8],
) -> impl Future<Item = R1, Error = CmdError> + 'sess {
async(static move || {
await!(self.send_cmd(59, on as u32, buf))?;
Ok(await!(self.wait_r1())?)
})
}
pub fn read_block<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
data: &'sess mut [u8],
address: u32,
timeout: usize,
) -> impl Future<Item = (), Error = CmdError> + 'sess {
async(static move || {
await!(self.wait_until_ready(timeout))?;
await!(self.send_cmd(17, address, buf))?;
await!(self.wait_r1())?.errck(false)?;
await!(self.wait_read_response(timeout))?;
await!(self.recv_bytes(data))?;
await!(self.recv_bytes(&mut buf[..2]))?;
self.data_crc_verify(data, buf)?;
Ok(())
})
}
pub fn read_blocks<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
data: &'sess mut [u8],
address: u32,
block_length: usize,
timeout: usize,
) -> impl Future<Item = R1, Error = CmdError> + 'sess {
async(static move || {
await!(self.wait_until_ready(timeout))?;
await!(self.send_cmd(18, address, buf))?;
await!(self.wait_r1())?.errck(false)?;
for data in data.chunks_mut(block_length) {
await!(self.wait_read_response(timeout))?;
await!(self.recv_bytes(data))?;
await!(self.recv_bytes(&mut buf[..2]))?;
self.data_crc_verify(data, buf)?;
}
await!(self.send_cmd(12, 0x0000_0000, buf))?;
Ok(await!(self.wait_r1())?)
})
}
pub fn write_block<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
data: &'sess [u8],
address: u32,
timeout: usize,
) -> impl Future<Item = (), Error = CmdError> + 'sess {
async(static move || {
await!(self.wait_until_ready(timeout))?;
await!(self.send_cmd(24, address, buf))?;
await!(self.wait_r1_and_until_ready())?.errck(false)?;
await!(self.send_data_block(BLOCK_START, data))?.errck()?;
await!(self.wait_until_ready(timeout))?;
let (_r1, status) = await!(self.send_status(buf))?;
status.errck()?;
Ok(())
})
}
pub fn write_blocks<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
data: &'sess [u8],
address: u32,
block_length: usize,
timeout: usize,
) -> impl Future<Item = (), Error = CmdError> + 'sess {
async(static move || {
await!(self.wait_until_ready(timeout))?;
await!(self.send_cmd(25, address, buf))?;
await!(self.wait_r1())?.errck(false)?;
let mut resp;
for data in data.chunks(block_length) {
await!(self.wait_until_ready(timeout))?;
resp = await!(self.send_data_block(BLOCK_START_MULTI_WRITE, data))?;
resp.errck()?;
}
await!(self.wait_until_ready(timeout))?;
await!(self.send_and_wait_until_ready(STOP_TRAN, timeout))?;
let (_r1, status) = await!(self.send_status(buf))?;
status.errck()?;
Ok(())
})
}
pub fn erase_blocks<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
start: u32,
end: u32,
timeout: usize,
) -> impl Future<Item = (), Error = CmdError> + 'sess {
async(static move || {
await!(self.wait_until_ready(timeout))?;
await!(self.send_cmd(32, start, buf))?;
await!(self.wait_r1())?.errck(false)?;
await!(self.send_cmd(33, end, buf))?;
await!(self.wait_r1())?.errck(false)?;
await!(self.send_cmd(33, 0x0000_0000, buf))?;
await!(self.wait_r1())?.errck(false)?;
Ok(())
})
}
fn startup_cycles<'sess>(
&'sess mut self,
) -> Box<Future<Item = (), Error = DmaError> + 'sess> {
unsafe {
self.0.dma_exchange(
&mut RX_FORGET,
false,
STARTUP_CYCLES,
&TX_IDLE,
false,
STARTUP_CYCLES,
)
}
}
fn send_cmd<'sess>(
&'sess mut self,
cmd: u8,
mut arg: u32,
buf: &'sess mut [u8],
) -> Box<Future<Item = (), Error = DmaError> + 'sess> {
assert!(buf.len() >= 6);
let (mut buf, mut crc) = (buf.as_mut_ptr(), Crc7::default());
unsafe {
let mut push = |byte| {
*buf = byte;
buf = buf.offset(1);
crc.add_byte(byte);
};
push(cmd | 0x40);
for _ in 0..4 {
arg = arg.rotate_left(8);
push(arg as u8);
}
}
unsafe {
*buf = crc.value() | 1;
buf = buf.offset(-5);
self.0.dma_exchange(&mut RX_FORGET, false, 6, buf, true, 6)
}
}
fn send_app_cmd<'sess>(
&'sess mut self,
cmd: u8,
arg: u32,
buf: &'sess mut [u8],
) -> impl Future<Item = (), Error = CmdError> + 'sess {
async(static move || {
await!(self.send_cmd(55, 0x0000_0000, buf))?;
await!(self.wait_r1_and_until_ready())?.errck(false)?;
await!(self.send_cmd(cmd, arg, buf))?;
Ok(())
})
}
fn send_and_wait_until_ready<'sess>(
&'sess mut self,
first_byte: u8,
max_skip: usize,
) -> Box<Future<Item = (), Error = CmdError> + 'sess> {
self.0.wait_byte(first_byte, max_skip, |byte| {
if byte == 0xFF {
Some(())
} else {
None
}
})
}
fn wait_until_ready<'sess>(
&'sess mut self,
max_skip: usize,
) -> Box<Future<Item = (), Error = CmdError> + 'sess> {
self.send_and_wait_until_ready(0xFF, max_skip)
}
fn wait_r1<'sess>(
&'sess mut self,
) -> Box<Future<Item = R1, Error = CmdError> + 'sess> {
self.0.wait_byte(0xFF, NCR, R1::try_from)
}
fn wait_r1_and_until_ready<'sess>(
&'sess mut self,
) -> Box<Future<Item = R1, Error = CmdError> + 'sess> {
let mut r1 = None;
self.0.wait_byte(0xFF, NCR, move |byte| {
if r1.is_none() {
r1 = R1::try_from(byte);
} else if byte == 0xFF {
return r1;
}
None
})
}
fn wait_r2<'sess>(
&'sess mut self,
) -> impl Future<Item = (R1, Status), Error = CmdError> + 'sess {
let mut r1 = None;
let resp = self.0.wait_byte(0xFF, NCR, move |byte| match r1 {
None => {
r1 = R1::try_from(byte);
if let Some(r1) = r1 {
if let Err(err) = r1.errck(true) {
return Some(Err(err));
}
}
None
}
Some(r1) => Some(Ok((r1, Status::new(byte)))),
});
async(static move || Ok(await!(resp)??))
}
fn wait_read_response<'sess>(
&'sess mut self,
max_skip: usize,
) -> impl Future<Item = (), Error = CmdError> + 'sess {
async(static move || {
await!(self.0.wait_byte(0xFF, max_skip, ReadResponse::try_from))?
.errck()?;
Ok(())
})
}
fn recv_bytes<'sess>(
&'sess mut self,
buf: &'sess mut [u8],
) -> Box<Future<Item = (), Error = DmaError> + 'sess> {
unsafe {
self.0.dma_exchange(
buf.as_mut_ptr(),
true,
buf.len(),
&TX_IDLE,
false,
buf.len(),
)
}
}
fn send_data_block<'sess>(
&'sess mut self,
token: u8,
data: &'sess [u8],
) -> impl Future<Item = WriteResponse, Error = DmaError> + 'sess {
async(static move || {
self.0.send_byte(token);
unsafe {
await!(self.0.dma_exchange(
&mut RX_FORGET,
false,
data.len() + 1,
data.as_ptr(),
true,
data.len(),
))?;
}
let crc = Crc16::from_bytes(data).value();
let mut resp: WriteResponse = unsafe { mem::uninitialized() };
let buf: [u8; 3] = [((crc & 0xFF_00) >> 8) as u8, crc as u8, 0xFF];
unsafe {
await!(self.0.dma_exchange(
&mut resp as *mut _ as *mut u8,
false,
3,
buf.as_ptr(),
true,
3
))?;
}
Ok(resp)
})
}
#[cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))]
#[inline(always)]
fn data_crc_verify(&self, data: &[u8], crc: &[u8]) -> Result<(), CmdError> {
assert!(crc.len() >= 2);
let check_crc = unsafe { u16::from_be(*(crc.as_ptr() as *const u16)) };
if Crc16::from_bytes(data).value() == check_crc {
Ok(())
} else {
Err(CmdError::DataCrc)
}
}
}