1use endbasic_std::spi::{SpiBus, SpiMode};
19use rppal::spi::{self, Bus, SlaveSelect, Spi};
20use std::io::Write;
21use std::path::Path;
22use std::{fs, io};
23
24const SPIDEV_BUFSIZ_PATH: &str = "/sys/module/spidev/parameters/bufsiz";
26
27fn spi_error_to_io_error(e: spi::Error) -> io::Error {
29 match e {
30 spi::Error::Io(e) => e,
31 e => io::Error::new(io::ErrorKind::InvalidInput, e.to_string()),
32 }
33}
34
35fn query_spi_bufsiz(path: Option<&Path>) -> io::Result<usize> {
38 let path = path.unwrap_or(Path::new(SPIDEV_BUFSIZ_PATH));
39
40 let content = match fs::read_to_string(path) {
41 Ok(content) => content,
42 Err(e) => {
43 return Err(io::Error::new(
44 e.kind(),
45 format!("Failed to read {}: {}", path.display(), e),
46 ));
47 }
48 };
49
50 let content = content.trim_end();
51
52 match content.parse::<usize>() {
53 Ok(i) => Ok(i),
54 Err(e) => Err(io::Error::new(
55 io::ErrorKind::InvalidData,
56 format!("Failed to read {}: invalid content: {}", path.display(), e),
57 )),
58 }
59}
60
61pub struct RppalSpiBus {
63 spi: Spi,
64 bufsiz: usize,
65}
66
67pub fn spi_bus_open(bus: u8, slave: u8, clock_hz: u32, mode: SpiMode) -> io::Result<RppalSpiBus> {
69 let bus = match bus {
70 0 => Bus::Spi0,
71 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Only bus 0 is supported")),
72 };
73
74 let slave = match slave {
75 0 => SlaveSelect::Ss0,
76 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Only slave 0 is supported")),
77 };
78
79 let mode = match mode {
80 SpiMode::Mode0 => spi::Mode::Mode0,
81 SpiMode::Mode1 => spi::Mode::Mode1,
82 SpiMode::Mode2 => spi::Mode::Mode2,
83 SpiMode::Mode3 => spi::Mode::Mode3,
84 };
85
86 let spi = Spi::new(bus, slave, clock_hz, mode).map_err(spi_error_to_io_error)?;
87
88 let bufsiz = query_spi_bufsiz(None)?;
89
90 Ok(RppalSpiBus { spi, bufsiz })
91}
92
93impl Write for RppalSpiBus {
94 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
95 self.spi.write(buf).map_err(spi_error_to_io_error)
96 }
97
98 fn flush(&mut self) -> io::Result<()> {
99 Ok(())
100 }
101}
102
103impl SpiBus for RppalSpiBus {
104 fn max_size(&self) -> usize {
105 self.bufsiz
106 }
107}