Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding HAL to support abstract underlying devices #4

Merged
merged 22 commits into from
Aug 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "embedded-spi"
description = "Rust embedded driver helper package (new releases at spi-hal)"
description = "Rust embedded driver helper package"
repository = "https://github.com/ryankurte/rust-spi-hal"
version = "0.6.2"
authors = ["Ryan Kurte <[email protected]>"]
Expand All @@ -17,23 +17,18 @@ hal-linux = [ "linux-embedded-hal" ]
default = [ "mock", "hal", "hal-cp2130", "hal-linux" ]

[dependencies]
embedded-hal = { version = "0.2.3", features = ["unproven"] }
embedded-hal = { version = "1.0.0-alpha.0" }
linux-embedded-hal = { version = "0.3.0", optional = true }
libc = { version = "0.2.54", optional = true }
log = "0.4.6"
serde = { version = "1.0.91", features = ["derive"], optional = true }
toml = { version = "0.5.1", optional = true }
structopt = { version = "0.3.11", optional = true }
simplelog = { version = "0.5.3", optional = true }
driver-cp2130 = { version = "0.3.1", optional = true }
driver-cp2130 = { version = "1.0.0-alpha.0", optional = true, features = ["transactional"] }


[patch.crates-io]
#embedded-hal = { git = "https://github.com/ryankurte/embedded-hal", branch = "feature/spi-transactions" }
#linux-embedded-hal = { git = "https://github.com/ryankurte/linux-embedded-hal.git", branch = "feature/spi-transactions" }
#driver-cp2130 = { git = "https://github.com/ryankurte/rust-driver-cp2130", branch = "master" }
embedded-hal = { git = "https://github.com/ryankurte/embedded-hal", branch = "feature/spi-transactions" }
linux-embedded-hal = { git = "https://github.com/ryankurte/linux-embedded-hal.git", branch = "feature/spi-transactions" }


#driver-cp2130 = { path = "../rust-driver-cp2130", optional=true }
#embedded-hal = { path = "../embedded-hal" }
#linux-embedded-hal = { path = "../linux-embedded-hal" }
17 changes: 10 additions & 7 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
//! as well as C ffi compatible spi_read and spi_write functions using these context pointers.

use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::blocking::spi::{Transactional};
use embedded_hal::digital::v2::OutputPin;

use crate::{PrefixWrite, PrefixRead};
use crate::wrapper::Wrapper;
use crate::Transactional;


/// Mark traits as cursed to provide a `Conv` implementation for FFI use
pub trait Cursed {}
Expand Down Expand Up @@ -48,7 +49,7 @@ impl<Spi, SpiError, CsPin, BusyPin, ReadyPin, ResetPin, PinError, Delay> Cursed
impl<Spi, SpiError, CsPin, BusyPin, ReadyPin, ResetPin, PinError, Delay>
Wrapper<Spi, SpiError, CsPin, BusyPin, ReadyPin, ResetPin, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Spi: Transactional<u8, Error = SpiError>,
CsPin: OutputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
Expand All @@ -70,8 +71,9 @@ where
// Execute command and handle errors
match s.spi_write(&prefix, &data) {
Ok(_) => 0,
Err(e) => {
s.err = Some(e);
Err(_e) => {
// TODO: removed this from wrapper
//s.err = Some(e);
-1
}
}
Expand All @@ -96,8 +98,9 @@ where
// Execute command and handle errors
match s.spi_read(&prefix, &mut data) {
Ok(_) => 0,
Err(e) => {
s.err = Some(e);
Err(_e) => {
// TODO: removed this from wrapper
//s.err = Some(e);
-1
}
}
Expand Down
67 changes: 67 additions & 0 deletions src/hal/cp2130.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

use std::convert::{TryFrom, TryInto};

use driver_cp2130::prelude::*;

use crate::*;
use super::{HalInst, HalPins, HalBase, HalSpi, HalInputPin, HalOutputPin, HalError, SpiConfig, PinConfig};

/// Convert a generic SPI config object into a CP2130 object
impl TryInto<driver_cp2130::SpiConfig> for SpiConfig {
type Error = HalError;

fn try_into(self) -> Result<driver_cp2130::SpiConfig, Self::Error> {
Ok(driver_cp2130::SpiConfig {
clock: SpiClock::try_from(self.baud as usize)?,
..driver_cp2130::SpiConfig::default()
})
}
}

/// CP2130 `Hal` implementation
pub struct Cp2130Driver;

impl Cp2130Driver {
/// Load base CP2130 instance
pub fn new<'a>(index: usize, spi: &SpiConfig, pins: &PinConfig) -> Result<HalInst<'a>, HalError> {
// Fetch the matching device and descriptor
let (device, descriptor) = Manager::device(Filter::default(), index)?;

// Create CP2130 object
let cp2130 = Cp2130::new(device, descriptor)?;

// Connect SPI
let spi_config = spi.clone().try_into()?;
let spi = cp2130.spi(0, spi_config)?;

// Connect pins

let chip_select = cp2130.gpio_out(pins.chip_select as u8, GpioMode::PushPull, GpioLevel::High)?;

let reset = cp2130.gpio_out(pins.reset as u8, GpioMode::PushPull, GpioLevel::High)?;

let busy = match pins.busy {
Some(p) => HalInputPin::Cp2130(cp2130.gpio_in(p as u8)?),
None => HalInputPin::None,
};

let ready = match pins.ready {
Some(p) => HalInputPin::Cp2130(cp2130.gpio_in(p as u8)?),
None => HalInputPin::None,
};

let pins = HalPins {
cs: HalOutputPin::Cp2130(chip_select),
reset: HalOutputPin::Cp2130(reset),
busy,
ready,
};

// Return object
Ok(HalInst{
base: HalBase::Cp2130(cp2130),
spi: HalSpi::Cp2130(spi),
pins,
})
}
}
38 changes: 38 additions & 0 deletions src/hal/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

/// Error type combining SPI and Pin errors for utility
#[derive(Debug)]
pub enum HalError {
InvalidConfig,
InvalidSpiMode,
NoPin,

#[cfg(feature = "hal-cp2130")]
Cp2130(driver_cp2130::Error),

#[cfg(feature = "hal-linux")]
Io(std::io::ErrorKind),

#[cfg(feature = "hal-linux")]
Sysfs(linux_embedded_hal::sysfs_gpio::Error),
}

#[cfg(feature = "hal-cp2130")]
impl From<driver_cp2130::Error> for HalError {
fn from(e: driver_cp2130::Error) -> Self {
Self::Cp2130(e)
}
}

#[cfg(feature = "hal-linux")]
impl From<std::io::Error> for HalError {
fn from(e: std::io::Error) -> Self {
Self::Io(e.kind())
}
}

#[cfg(feature = "hal-linux")]
impl From<linux_embedded_hal::sysfs_gpio::Error> for HalError {
fn from(e: linux_embedded_hal::sysfs_gpio::Error) -> Self {
Self::Sysfs(e)
}
}
96 changes: 96 additions & 0 deletions src/hal/linux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

extern crate linux_embedded_hal;
pub use linux_embedded_hal::sysfs_gpio::{Direction, Error as PinError};
pub use linux_embedded_hal::{spidev, Delay, SysfsPin as Pindev, Spidev, spidev::SpiModeFlags};

use super::*;

pub struct LinuxDriver;

impl LinuxDriver {
/// Load an SPI device using the provided configuration
pub fn new<'a>(path: &str, spi: &SpiConfig, pins: &PinConfig) -> Result<HalInst<'a>, HalError> {
let mut flags = match spi.mode {
0 => SpiModeFlags::SPI_MODE_0,
1 => SpiModeFlags::SPI_MODE_1,
2 => SpiModeFlags::SPI_MODE_2,
3 => SpiModeFlags::SPI_MODE_3,
_ => return Err(HalError::InvalidSpiMode),
};

flags |= SpiModeFlags::SPI_NO_CS;

debug!(
"Conecting to spi: {} at {} baud with mode: {:?}",
path, spi.baud, flags
);

let spi = load_spi(path, spi.baud, flags)?;

let pins = Self::load_pins(pins)?;

Ok(HalInst{
base: HalBase::None,
spi: HalSpi::Linux(spi),
pins,
})
}

/// Load pins using the provided config
fn load_pins<'a>(pins: &PinConfig) -> Result<HalPins<'a>, HalError> {

let chip_select = load_pin(pins.chip_select, Direction::Out)?;

let reset = load_pin(pins.reset, Direction::Out)?;

let busy = match pins.busy {
Some(p) => HalInputPin::Linux(load_pin(p, Direction::In)?),
None => HalInputPin::None,
};

let ready = match pins.ready {
Some(p) => HalInputPin::Linux(load_pin(p, Direction::In)?),
None => HalInputPin::None,
};

let pins = HalPins{
cs: HalOutputPin::Linux(chip_select),
reset: HalOutputPin::Linux(reset),
busy,
ready,
};

Ok(pins)
}
}

/// Load an SPI device using the provided configuration
fn load_spi(path: &str, baud: u32, mode: spidev::SpiModeFlags) -> Result<Spidev, HalError> {
debug!(
"Conecting to spi: {} at {} baud with mode: {:?}",
path, baud, mode
);

let mut spi = Spidev::open(path)?;

let mut config = spidev::SpidevOptions::new();
config.mode(SpiModeFlags::SPI_MODE_0 | SpiModeFlags::SPI_NO_CS);
config.max_speed_hz(baud);
spi.configure(&config)?;

Ok(spi)
}

/// Load a Pin using the provided configuration
fn load_pin(index: u64, direction: Direction) -> Result<Pindev, HalError> {
debug!(
"Connecting to pin: {} with direction: {:?}",
index, direction
);

let p = Pindev::new(index);
p.export()?;
p.set_direction(direction)?;

Ok(p)
}
Loading