Skip to content

Commit

Permalink
Merge pull request #4 from ryankurte/feature/hal
Browse files Browse the repository at this point in the history
Adding HAL to support abstract underlying devices
  • Loading branch information
ryankurte authored Aug 1, 2020
2 parents a31c964 + 3c38035 commit 2e45501
Show file tree
Hide file tree
Showing 9 changed files with 853 additions and 374 deletions.
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

0 comments on commit 2e45501

Please sign in to comment.