use endbasic_std::spi::{SpiBus, SpiMode};
use rppal::spi::{self, Bus, SlaveSelect, Spi};
use std::io::Write;
use std::path::Path;
use std::{fs, io};
const SPIDEV_BUFSIZ_PATH: &str = "/sys/module/spidev/parameters/bufsiz";
fn spi_error_to_io_error(e: spi::Error) -> io::Error {
match e {
spi::Error::Io(e) => e,
e => io::Error::new(io::ErrorKind::InvalidInput, e.to_string()),
}
}
fn query_spi_bufsiz(path: Option<&Path>) -> io::Result<usize> {
let path = path.unwrap_or(Path::new(SPIDEV_BUFSIZ_PATH));
let content = match fs::read_to_string(path) {
Ok(content) => content,
Err(e) => {
return Err(io::Error::new(
e.kind(),
format!("Failed to read {}: {}", path.display(), e),
));
}
};
let content = content.trim_end();
match content.parse::<usize>() {
Ok(i) => Ok(i),
Err(e) => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Failed to read {}: invalid content: {}", path.display(), e),
)),
}
}
pub struct RppalSpiBus {
spi: Spi,
bufsiz: usize,
}
pub fn spi_bus_open(bus: u8, slave: u8, clock_hz: u32, mode: SpiMode) -> io::Result<RppalSpiBus> {
let bus = match bus {
0 => Bus::Spi0,
_ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Only bus 0 is supported")),
};
let slave = match slave {
0 => SlaveSelect::Ss0,
_ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Only slave 0 is supported")),
};
let mode = match mode {
SpiMode::Mode0 => spi::Mode::Mode0,
SpiMode::Mode1 => spi::Mode::Mode1,
SpiMode::Mode2 => spi::Mode::Mode2,
SpiMode::Mode3 => spi::Mode::Mode3,
};
let spi = Spi::new(bus, slave, clock_hz, mode).map_err(spi_error_to_io_error)?;
let bufsiz = query_spi_bufsiz(None)?;
Ok(RppalSpiBus { spi, bufsiz })
}
impl Write for RppalSpiBus {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.spi.write(buf).map_err(spi_error_to_io_error)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl SpiBus for RppalSpiBus {
fn max_size(&self) -> usize {
self.bufsiz
}
}