pub use crate::ll_api::{SpiBusBitOrder, SpiBusDataSize, SpiBusId, SpiBusMode};
use crate::{ll_api::ll_cmd::*, tick::Delay};
use core::{cmp::min, ptr};
use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::Operation};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
Code(i32),
}
pub struct Config {
pub baudrate: u32,
pub mode: SpiBusMode,
pub size: SpiBusDataSize,
pub order: SpiBusBitOrder,
}
impl Default for Config {
fn default() -> Self {
Self {
baudrate: 8_000_000,
mode: SpiBusMode::Mode0,
size: SpiBusDataSize::DataSize8,
order: SpiBusBitOrder::MsbFirst,
}
}
}
#[derive(Clone, Debug)]
pub struct SpiBus {
bus: SpiBusId,
}
impl SpiBus {
pub fn new(bus: SpiBusId, config: &Config) -> Self {
let flags = config.size as u32 | config.order as u32;
ll_invoke_inner!(INVOKE_ID_SPI_INIT, bus, config.mode, flags, config.baudrate);
SpiBus { bus }
}
pub fn to_device<NSS: OutputPin>(self, nss: NSS) -> SpiDevice<NSS> {
SpiDevice { bus: self, nss }
}
fn blocking_read(&mut self, words: &mut [u8]) -> i32 {
ll_invoke_inner!(
INVOKE_ID_SPI_BLOCKING_RW,
self.bus,
ptr::null::<u8>(),
words.as_mut_ptr(),
words.len()
)
}
fn blocking_write(&mut self, words: &[u8]) -> i32 {
ll_invoke_inner!(
INVOKE_ID_SPI_BLOCKING_RW,
self.bus,
words.as_ptr(),
ptr::null::<u8>(),
words.len()
)
}
fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> i32 {
let size = min(read.len(), write.len());
ll_invoke_inner!(
INVOKE_ID_SPI_BLOCKING_RW,
self.bus,
write.as_ptr(),
read.as_ptr(),
size
)
}
fn blocking_transfer_in_place(&mut self, words: &mut [u8]) -> i32 {
let rw_ptr = words.as_ptr();
ll_invoke_inner!(
INVOKE_ID_SPI_BLOCKING_RW,
self.bus,
rw_ptr,
rw_ptr,
words.len()
)
}
}
impl Drop for SpiBus {
fn drop(&mut self) {
ll_invoke_inner!(INVOKE_ID_SPI_DEINIT, self.bus);
}
}
impl embedded_hal::spi::ErrorType for SpiBus {
type Error = Error;
}
impl embedded_hal::spi::SpiBus for SpiBus {
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
let result = self.blocking_read(words);
if result == 0 {
return Ok(());
}
return Err(Error::Code(result));
}
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let result = self.blocking_write(words);
if result == 0 {
return Ok(());
}
return Err(Error::Code(result));
}
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
let result = self.blocking_transfer(read, write);
if result == 0 {
return Ok(());
}
return Err(Error::Code(result));
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
let result = self.blocking_transfer_in_place(words);
if result == 0 {
return Ok(());
}
return Err(Error::Code(result));
}
}
impl embedded_hal::spi::Error for Error {
fn kind(&self) -> embedded_hal::spi::ErrorKind {
match *self {
Self::Code(_) => embedded_hal::spi::ErrorKind::Other,
}
}
}
pub struct SpiDevice<NSS> {
bus: SpiBus,
nss: NSS,
}
impl<NSS: OutputPin> SpiDevice<NSS> {
pub fn new(bus: SpiBus, nss: NSS) -> Self {
SpiDevice { bus, nss }
}
}
impl<NSS: OutputPin> embedded_hal::spi::ErrorType for SpiDevice<NSS> {
type Error = Error;
}
impl<NSS: OutputPin> embedded_hal::spi::SpiDevice for SpiDevice<NSS> {
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
let mut result = Ok(());
self.nss.set_low().ok();
for op in operations {
match op {
Operation::Read(words) => {
let ret = self.bus.blocking_read(words);
if ret != 0 {
result = Err(Error::Code(ret));
}
}
Operation::Write(words) => {
let ret = self.bus.blocking_write(words);
if ret != 0 {
result = Err(Error::Code(ret));
}
}
Operation::Transfer(rd_words, wr_words) => {
let ret = self.bus.blocking_transfer(rd_words, wr_words);
if ret != 0 {
result = Err(Error::Code(ret));
}
}
Operation::TransferInPlace(words) => {
let ret = self.bus.blocking_transfer_in_place(words);
if ret != 0 {
result = Err(Error::Code(ret));
}
}
Operation::DelayNs(ns) => {
let mut delay = Delay::new();
delay.delay_ns(*ns);
}
}
}
self.nss.set_high().ok();
result
}
}