use super::SpiModeFlags;
use nix::{ioctl_read, ioctl_write_buf, ioctl_write_ptr};
use std::io;
use std::marker::PhantomData;
use std::os::unix::prelude::*;
fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
match res {
Ok(r) => Ok(r),
Err(err) => Err(err.into()),
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Default)]
#[repr(C)]
pub struct spi_ioc_transfer<'a, 'b> {
tx_buf: u64,
rx_buf: u64,
len: u32,
pub speed_hz: u32,
pub delay_usecs: u16,
pub bits_per_word: u8,
pub cs_change: u8,
pub pad: u32,
tx_buf_ref: PhantomData<&'a [u8]>,
rx_buf_ref: PhantomData<&'b mut [u8]>,
}
impl<'a, 'b> spi_ioc_transfer<'a, 'b> {
pub fn read(buff: &'b mut [u8]) -> Self {
spi_ioc_transfer {
rx_buf: buff.as_ptr() as *const () as usize as u64,
len: buff.len() as u32,
..Default::default()
}
}
pub fn write(buff: &'a [u8]) -> Self {
spi_ioc_transfer {
tx_buf: buff.as_ptr() as *const () as usize as u64,
len: buff.len() as u32,
..Default::default()
}
}
pub fn read_write(tx_buf: &'a [u8], rx_buf: &'b mut [u8]) -> Self {
assert_eq!(tx_buf.len(), rx_buf.len());
spi_ioc_transfer {
rx_buf: rx_buf.as_ptr() as *const () as usize as u64,
tx_buf: tx_buf.as_ptr() as *const () as usize as u64,
len: tx_buf.len() as u32,
..Default::default()
}
}
pub fn read_write_in_place(buf: &'a mut [u8]) -> Self {
spi_ioc_transfer {
rx_buf: buf.as_ptr() as *const () as usize as u64,
tx_buf: buf.as_ptr() as *const () as usize as u64,
len: buf.len() as u32,
..Default::default()
}
}
pub fn delay(microseconds: u16) -> Self {
spi_ioc_transfer {
delay_usecs: microseconds,
len: 0,
..Default::default()
}
}
}
mod ioctl {
use super::*;
const SPI_IOC_MAGIC: u8 = b'k';
const SPI_IOC_NR_TRANSFER: u8 = 0;
const SPI_IOC_NR_MODE: u8 = 1;
const SPI_IOC_NR_LSB_FIRST: u8 = 2;
const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
const SPI_IOC_NR_MODE32: u8 = 5;
ioctl_read!(get_mode_u8, SPI_IOC_MAGIC, SPI_IOC_NR_MODE, u8);
ioctl_read!(get_mode_u32, SPI_IOC_MAGIC, SPI_IOC_NR_MODE32, u32);
ioctl_write_ptr!(set_mode, SPI_IOC_MAGIC, SPI_IOC_NR_MODE, u8);
ioctl_write_ptr!(set_mode32, SPI_IOC_MAGIC, SPI_IOC_NR_MODE32, u32);
ioctl_read!(get_lsb_first, SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST, u8);
ioctl_write_ptr!(set_lsb_first, SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST, u8);
ioctl_read!(
get_bits_per_word,
SPI_IOC_MAGIC,
SPI_IOC_NR_BITS_PER_WORD,
u8
);
ioctl_write_ptr!(
set_bits_per_word,
SPI_IOC_MAGIC,
SPI_IOC_NR_BITS_PER_WORD,
u8
);
ioctl_read!(
get_max_speed_hz,
SPI_IOC_MAGIC,
SPI_IOC_NR_MAX_SPEED_HZ,
u32
);
ioctl_write_ptr!(
set_max_speed_hz,
SPI_IOC_MAGIC,
SPI_IOC_NR_MAX_SPEED_HZ,
u32
);
ioctl_write_ptr!(
spidev_transfer,
SPI_IOC_MAGIC,
SPI_IOC_NR_TRANSFER,
spi_ioc_transfer
);
ioctl_write_buf!(
spidev_transfer_buf,
SPI_IOC_MAGIC,
SPI_IOC_NR_TRANSFER,
spi_ioc_transfer
);
}
pub type SpidevTransfer<'a, 'b> = spi_ioc_transfer<'a, 'b>;
pub fn get_mode(fd: RawFd) -> io::Result<u8> {
let mut mode: u8 = 0;
from_nix_result(unsafe { ioctl::get_mode_u8(fd, &mut mode) })?;
Ok(mode)
}
pub fn get_mode_u32(fd: RawFd) -> io::Result<u32> {
let mut mode: u32 = 0;
from_nix_result(unsafe { ioctl::get_mode_u32(fd, &mut mode) })?;
Ok(mode)
}
pub fn set_mode(fd: RawFd, mode: SpiModeFlags) -> io::Result<()> {
if (mode.bits() & 0xFFFFFF00) != 0 {
from_nix_result(unsafe { ioctl::set_mode32(fd, &mode.bits()) })?;
} else {
let bits: u8 = mode.bits() as u8;
from_nix_result(unsafe { ioctl::set_mode(fd, &bits) })?;
}
Ok(())
}
pub fn get_lsb_first(fd: RawFd) -> io::Result<u8> {
let mut lsb_first: u8 = 0;
from_nix_result(unsafe { ioctl::get_lsb_first(fd, &mut lsb_first) })?;
Ok(lsb_first)
}
pub fn set_lsb_first(fd: RawFd, lsb_first: bool) -> io::Result<()> {
let lsb_first_value: u8 = if lsb_first { 1 } else { 0 };
from_nix_result(unsafe { ioctl::set_lsb_first(fd, &lsb_first_value) })?;
Ok(())
}
pub fn get_bits_per_word(fd: RawFd) -> io::Result<u8> {
let mut bits_per_word: u8 = 0;
from_nix_result(unsafe { ioctl::get_bits_per_word(fd, &mut bits_per_word) })?;
Ok(bits_per_word)
}
pub fn set_bits_per_word(fd: RawFd, bits_per_word: u8) -> io::Result<()> {
from_nix_result(unsafe { ioctl::set_bits_per_word(fd, &bits_per_word) })?;
Ok(())
}
pub fn get_max_speed_hz(fd: RawFd) -> io::Result<u32> {
let mut max_speed_hz: u32 = 0;
from_nix_result(unsafe { ioctl::get_max_speed_hz(fd, &mut max_speed_hz) })?;
Ok(max_speed_hz)
}
pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
from_nix_result(unsafe { ioctl::set_max_speed_hz(fd, &max_speed_hz) })?;
Ok(())
}
pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
from_nix_result(unsafe { ioctl::spidev_transfer(fd, transfer) })?;
Ok(())
}
pub fn transfer_multiple(fd: RawFd, transfers: &mut [SpidevTransfer]) -> io::Result<()> {
from_nix_result(unsafe { ioctl::spidev_transfer_buf(fd, transfers) })?;
Ok(())
}