use std::{
sync::{Arc, Mutex},
time::{Duration, Instant},
};
pub use embedded_hal::spi::Mode as SpiMode;
use rusb::{Context as UsbContext, Device as UsbDevice, DeviceDescriptor};
pub mod device;
pub mod manager;
pub mod prelude;
use crate::device::*;
pub use crate::device::{GpioLevel, GpioMode, SpiClock, SpiConfig, UsbOptions};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("USB error: {0}")]
Usb(rusb::Error),
#[error("No matching endpoint languages found")]
NoLanguages,
#[error("No valid endpoint configuration found")]
Configurations,
#[error("No matching endpoint found")]
Endpoint,
#[error("GPIO pin already in use")]
GpioInUse,
#[error("Invalid SPI index")]
InvalidIndex,
#[error("Invalid SPI baud rate")]
InvalidBaud,
}
impl From<rusb::Error> for Error {
fn from(e: rusb::Error) -> Self {
Error::Usb(e)
}
}
pub struct Cp2130 {
inner: Arc<Mutex<Inner>>,
info: Info,
}
pub trait Device {
fn spi_read(&self, buff: &mut [u8]) -> Result<usize, Error>;
fn spi_write(&self, buff: &[u8]) -> Result<(), Error>;
fn spi_write_read(&self, buff_out: &[u8], buff_in: &mut [u8]) -> Result<usize, Error>;
fn version(&self) -> Result<u16, Error>;
fn set_gpio_mode_level(&self, pin: u8, mode: GpioMode, level: GpioLevel) -> Result<(), Error>;
fn get_gpio_values(&self) -> Result<GpioLevels, Error>;
fn get_gpio_level(&self, pin: u8) -> Result<bool, Error>;
}
impl Cp2130 {
pub fn new(
device: UsbDevice<UsbContext>,
descriptor: DeviceDescriptor,
options: UsbOptions,
) -> Result<Self, Error> {
let (inner, info) = Inner::new(device, descriptor, options)?;
let inner = Arc::new(Mutex::new(inner));
Ok(Self { info, inner })
}
pub fn info(&self) -> Info {
self.info.clone()
}
pub fn reset(&self) -> Result<(), Error> {
self.inner.lock().unwrap().reset()
}
pub fn spi(&self, channel: u8, config: SpiConfig, cs_pin: Option<u8>) -> Result<Spi, Error> {
let mut inner = self.inner.lock().unwrap();
if let Some(cs) = cs_pin {
inner.set_gpio_mode_level(cs, GpioMode::PushPull, GpioLevel::High)?;
}
inner.spi_configure(channel, config)?;
Ok(Spi {
inner: self.inner.clone(),
_channel: channel,
cs: cs_pin,
})
}
pub fn gpio_out(
&self,
index: u8,
mode: GpioMode,
level: GpioLevel,
) -> Result<OutputPin, Error> {
let mut inner = self.inner.lock().unwrap();
if inner.gpio_allocated[index as usize] {
return Err(Error::GpioInUse);
}
inner.set_gpio_mode_level(index, mode, level)?;
inner.gpio_allocated[index as usize] = true;
Ok(OutputPin {
index,
mode,
inner: self.inner.clone(),
})
}
pub fn gpio_in(&self, index: u8) -> Result<InputPin, Error> {
let mut inner = self.inner.lock().unwrap();
if inner.gpio_allocated[index as usize] {
return Err(Error::GpioInUse);
}
inner.set_gpio_mode_level(index, GpioMode::Input, GpioLevel::Low)?;
inner.gpio_allocated[index as usize] = true;
Ok(InputPin {
index,
inner: self.inner.clone(),
})
}
}
impl Device for Cp2130 {
fn spi_read(&self, buff: &mut [u8]) -> Result<usize, Error> {
let mut inner = self.inner.lock().unwrap();
inner.spi_read(buff)
}
fn spi_write(&self, buff: &[u8]) -> Result<(), Error> {
let mut inner = self.inner.lock().unwrap();
inner.spi_write(buff)
}
fn spi_write_read(&self, buff_out: &[u8], buff_in: &mut [u8]) -> Result<usize, Error> {
let mut inner = self.inner.lock().unwrap();
inner.spi_write_read(buff_out, buff_in)
}
fn version(&self) -> Result<u16, Error> {
let mut inner = self.inner.lock().unwrap();
inner.version()
}
fn set_gpio_mode_level(&self, pin: u8, mode: GpioMode, level: GpioLevel) -> Result<(), Error> {
let mut inner = self.inner.lock().unwrap();
inner.set_gpio_mode_level(pin, mode, level)
}
fn get_gpio_values(&self) -> Result<GpioLevels, Error> {
let mut inner = self.inner.lock().unwrap();
inner.get_gpio_values()
}
fn get_gpio_level(&self, pin: u8) -> Result<bool, Error> {
let mut inner = self.inner.lock().unwrap();
inner.get_gpio_level(pin)
}
}
pub struct Spi {
_channel: u8,
inner: Arc<Mutex<Inner>>,
cs: Option<u8>,
}
use embedded_hal::spi::Operation as SpiOp;
impl embedded_hal::spi::SpiDevice<u8> for Spi {
fn transaction(&mut self, operations: &mut [SpiOp<'_, u8>]) -> Result<(), Self::Error> {
let mut i = self.inner.lock().unwrap();
if let Some(cs) = self.cs {
i.set_gpio_mode_level(cs, GpioMode::PushPull, GpioLevel::Low)?;
}
for o in operations {
let err = match o {
SpiOp::Write(w) => i.spi_write(w).err(),
SpiOp::Transfer(r, w) => i.spi_write_read(w, r).err(),
SpiOp::TransferInPlace(b) => {
let out = b.to_vec();
i.spi_write_read(&out, b).err()
}
SpiOp::Read(r) => {
let out = vec![0u8; r.len()];
i.spi_write_read(&out, r).err()
}
SpiOp::DelayNs(ns) => {
let now = Instant::now();
while now.elapsed() < Duration::from_nanos(*ns as u64) {}
None
}
};
if let Some(e) = err {
if let Some(cs) = self.cs {
i.set_gpio_mode_level(cs, GpioMode::PushPull, GpioLevel::High)?;
}
return Err(e);
}
}
if let Some(cs) = self.cs {
i.set_gpio_mode_level(cs, GpioMode::PushPull, GpioLevel::Low)?;
}
Ok(())
}
}
impl embedded_hal::spi::ErrorType for Spi {
type Error = Error;
}
impl embedded_hal::spi::Error for Error {
fn kind(&self) -> embedded_hal::spi::ErrorKind {
embedded_hal::spi::ErrorKind::Other
}
}
pub struct InputPin {
index: u8,
inner: Arc<Mutex<Inner>>,
}
impl embedded_hal::digital::InputPin for InputPin {
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.inner.lock().unwrap().get_gpio_level(self.index)
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
let v = self.is_high()?;
Ok(!v)
}
}
impl embedded_hal::digital::ErrorType for InputPin {
type Error = Error;
}
impl embedded_hal::digital::Error for Error {
fn kind(&self) -> embedded_hal::digital::ErrorKind {
embedded_hal::digital::ErrorKind::Other
}
}
pub struct OutputPin {
index: u8,
mode: GpioMode,
inner: Arc<Mutex<Inner>>,
}
impl embedded_hal::digital::OutputPin for OutputPin {
fn set_high(&mut self) -> Result<(), Self::Error> {
self.inner
.lock()
.unwrap()
.set_gpio_mode_level(self.index, self.mode, GpioLevel::High)
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.inner
.lock()
.unwrap()
.set_gpio_mode_level(self.index, self.mode, GpioLevel::Low)
}
}
impl embedded_hal::digital::ErrorType for OutputPin {
type Error = Error;
}