Skip to content

Add transactional SPI #35

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

Merged
merged 6 commits into from
Nov 17, 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
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
[package]
authors = ["Jorge Aparicio <jorge@japaric.io>"]
authors = [
"The Embedded Linux Team <embedded-linux@teams.rust-embedded.org>",
"Jorge Aparicio <jorge@japaric.io>"
]
categories = ["embedded", "hardware-support"]
description = "Implementation of the `embedded-hal` traits for Linux devices"
keywords = ["Linux", "hal"]
license = "MIT OR Apache-2.0"
name = "linux-embedded-hal"
repository = "https://github.com/japaric/linux-embedded-hal"
repository = "https://github.com/rust-embedded/linux-embedded-hal"
version = "0.3.0"
edition = "2018"

[features]
gpio_sysfs = ["sysfs_gpio"]
Expand All @@ -32,3 +36,4 @@ openpty = "0.1.0"
# we don't need the `Error` implementation
default-features = false
version = "0.2.2"

4 changes: 2 additions & 2 deletions src/cdev_pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl CdevPin {
}
}

impl hal::digital::OutputPin for CdevPin {
impl embedded_hal::digital::OutputPin for CdevPin {
type Error = gpio_cdev::errors::Error;

fn try_set_low(&mut self) -> Result<(), Self::Error> {
Expand All @@ -27,7 +27,7 @@ impl hal::digital::OutputPin for CdevPin {
}
}

impl hal::digital::InputPin for CdevPin {
impl embedded_hal::digital::InputPin for CdevPin {
type Error = gpio_cdev::errors::Error;

fn try_is_high(&self) -> Result<bool, Self::Error> {
Expand Down
84 changes: 58 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@

#![deny(missing_docs)]

extern crate cast;
extern crate core;
extern crate embedded_hal as hal;
pub extern crate i2cdev;
pub extern crate nb;
pub extern crate serial_core;
pub extern crate serial_unix;
pub extern crate spidev;
use cast;
pub use i2cdev;
pub use nb;
pub use serial_core;
pub use serial_unix;
pub use spidev;

#[cfg(feature = "gpio_sysfs")]
pub extern crate sysfs_gpio;
pub use sysfs_gpio;

#[cfg(feature = "gpio_cdev")]
pub extern crate gpio_cdev;
pub use gpio_cdev;


use core::convert::Infallible;
use std::io::{self, Write};
Expand All @@ -34,7 +33,7 @@ use std::time::Duration;
use std::{ops, thread};

use cast::{u32, u64};
use hal::blocking::i2c::Operation as I2cOperation;
use embedded_hal::blocking::i2c::Operation as I2cOperation;
use i2cdev::core::{I2CDevice, I2CMessage, I2CTransfer};
use i2cdev::linux::LinuxI2CMessage;
use spidev::SpidevTransfer;
Expand Down Expand Up @@ -63,7 +62,7 @@ pub use sysfs_pin::SysfsPin;
/// Empty struct that provides delay functionality on top of `thread::sleep`
pub struct Delay;

impl hal::blocking::delay::DelayUs<u8> for Delay {
impl embedded_hal::blocking::delay::DelayUs<u8> for Delay {
type Error = Infallible;

fn try_delay_us(&mut self, n: u8) -> Result<(), Self::Error> {
Expand All @@ -72,7 +71,7 @@ impl hal::blocking::delay::DelayUs<u8> for Delay {
}
}

impl hal::blocking::delay::DelayUs<u16> for Delay {
impl embedded_hal::blocking::delay::DelayUs<u16> for Delay {
type Error = Infallible;

fn try_delay_us(&mut self, n: u16) -> Result<(), Self::Error> {
Expand All @@ -81,7 +80,7 @@ impl hal::blocking::delay::DelayUs<u16> for Delay {
}
}

impl hal::blocking::delay::DelayUs<u32> for Delay {
impl embedded_hal::blocking::delay::DelayUs<u32> for Delay {
type Error = Infallible;

fn try_delay_us(&mut self, n: u32) -> Result<(), Self::Error> {
Expand All @@ -93,7 +92,7 @@ impl hal::blocking::delay::DelayUs<u32> for Delay {
}
}

impl hal::blocking::delay::DelayUs<u64> for Delay {
impl embedded_hal::blocking::delay::DelayUs<u64> for Delay {
type Error = Infallible;

fn try_delay_us(&mut self, n: u64) -> Result<(), Self::Error> {
Expand All @@ -105,7 +104,7 @@ impl hal::blocking::delay::DelayUs<u64> for Delay {
}
}

impl hal::blocking::delay::DelayMs<u8> for Delay {
impl embedded_hal::blocking::delay::DelayMs<u8> for Delay {
type Error = Infallible;

fn try_delay_ms(&mut self, n: u8) -> Result<(), Self::Error> {
Expand All @@ -114,7 +113,7 @@ impl hal::blocking::delay::DelayMs<u8> for Delay {
}
}

impl hal::blocking::delay::DelayMs<u16> for Delay {
impl embedded_hal::blocking::delay::DelayMs<u16> for Delay {
type Error = Infallible;

fn try_delay_ms(&mut self, n: u16) -> Result<(), Self::Error> {
Expand All @@ -123,7 +122,7 @@ impl hal::blocking::delay::DelayMs<u16> for Delay {
}
}

impl hal::blocking::delay::DelayMs<u32> for Delay {
impl embedded_hal::blocking::delay::DelayMs<u32> for Delay {
type Error = Infallible;

fn try_delay_ms(&mut self, n: u32) -> Result<(), Self::Error> {
Expand All @@ -132,7 +131,7 @@ impl hal::blocking::delay::DelayMs<u32> for Delay {
}
}

impl hal::blocking::delay::DelayMs<u64> for Delay {
impl embedded_hal::blocking::delay::DelayMs<u64> for Delay {
type Error = Infallible;

fn try_delay_ms(&mut self, n: u64) -> Result<(), Self::Error> {
Expand Down Expand Up @@ -175,7 +174,7 @@ impl I2cdev {
}
}

impl hal::blocking::i2c::Read for I2cdev {
impl embedded_hal::blocking::i2c::Read for I2cdev {
type Error = i2cdev::linux::LinuxI2CError;

fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
Expand All @@ -184,7 +183,7 @@ impl hal::blocking::i2c::Read for I2cdev {
}
}

impl hal::blocking::i2c::Write for I2cdev {
impl embedded_hal::blocking::i2c::Write for I2cdev {
type Error = i2cdev::linux::LinuxI2CError;

fn try_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
Expand All @@ -193,7 +192,7 @@ impl hal::blocking::i2c::Write for I2cdev {
}
}

impl hal::blocking::i2c::WriteRead for I2cdev {
impl embedded_hal::blocking::i2c::WriteRead for I2cdev {
type Error = i2cdev::linux::LinuxI2CError;

fn try_write_read(
Expand All @@ -203,12 +202,15 @@ impl hal::blocking::i2c::WriteRead for I2cdev {
buffer: &mut [u8],
) -> Result<(), Self::Error> {
self.set_address(address)?;
let mut messages = [LinuxI2CMessage::write(bytes), LinuxI2CMessage::read(buffer)];
let mut messages = [
LinuxI2CMessage::write(bytes),
LinuxI2CMessage::read(buffer),
];
self.inner.transfer(&mut messages).map(drop)
}
}

impl hal::blocking::i2c::Transactional for I2cdev {
impl embedded_hal::blocking::i2c::Transactional for I2cdev {
type Error = i2cdev::linux::LinuxI2CError;

fn try_exec(&mut self, address: u8, operations: &mut [I2cOperation]) -> Result<(), Self::Error>
Expand Down Expand Up @@ -259,7 +261,7 @@ impl Spidev {
}
}

impl hal::blocking::spi::Transfer<u8> for Spidev {
impl embedded_hal::blocking::spi::Transfer<u8> for Spidev {
type Error = io::Error;

fn try_transfer<'b>(&mut self, buffer: &'b mut [u8]) -> io::Result<&'b [u8]> {
Expand All @@ -270,14 +272,44 @@ impl hal::blocking::spi::Transfer<u8> for Spidev {
}
}

impl hal::blocking::spi::Write<u8> for Spidev {
impl embedded_hal::blocking::spi::Write<u8> for Spidev {
type Error = io::Error;

fn try_write(&mut self, buffer: &[u8]) -> io::Result<()> {
self.0.write_all(buffer)
}
}

pub use embedded_hal::blocking::spi::{Operation as SpiOperation};

/// Transactional implementation batches SPI operations into a single transaction
impl embedded_hal::blocking::spi::Transactional<u8> for Spidev {
type Error = io::Error;

fn try_exec<'a>(&mut self, operations: &mut [SpiOperation<'a, u8>]) -> Result<(), Self::Error> {

// Map types from generic to linux objects
let mut messages: Vec<_> = operations.iter_mut().map(|a| {
match a {
SpiOperation::Write(w) => SpidevTransfer::write(w),
SpiOperation::Transfer(r) => {
// Clone read to write pointer
// SPIdev is okay with having w == r but this is tricky to achieve in safe rust
let w = unsafe {
let p = r.as_ptr();
std::slice::from_raw_parts(p, r.len())
};

SpidevTransfer::read_write(w, r)
},
}
}).collect();

// Execute transfer
self.0.transfer_multiple(&mut messages)
}
}

impl ops::Deref for Spidev {
type Target = spidev::Spidev;

Expand Down
7 changes: 3 additions & 4 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::path::Path;

use nb;

use hal;
use serial_core;
use serial_unix::TTYPort;

Expand All @@ -30,7 +29,7 @@ fn translate_io_errors(err: std::io::Error) -> nb::Error<IoErrorKind> {
}
}

impl hal::serial::Read<u8> for Serial {
impl embedded_hal::serial::Read<u8> for Serial {
type Error = IoErrorKind;

fn try_read(&mut self) -> nb::Result<u8, Self::Error> {
Expand All @@ -44,7 +43,7 @@ impl hal::serial::Read<u8> for Serial {
}
}

impl hal::serial::Write<u8> for Serial {
impl embedded_hal::serial::Write<u8> for Serial {
type Error = IoErrorKind;

fn try_write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
Expand All @@ -61,7 +60,7 @@ impl hal::serial::Write<u8> for Serial {
mod test {
use std::path::Path;

use hal::serial::{Read, Write};
use embedded_hal::serial::{Read, Write};
use std::io::{Read as IoRead, Write as IoWrite};

use super::*;
Expand Down
4 changes: 2 additions & 2 deletions src/sysfs_pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl SysfsPin {
}
}

impl hal::digital::OutputPin for SysfsPin {
impl embedded_hal::digital::OutputPin for SysfsPin {
type Error = sysfs_gpio::Error;

fn try_set_low(&mut self) -> Result<(), Self::Error> {
Expand All @@ -38,7 +38,7 @@ impl hal::digital::OutputPin for SysfsPin {
}
}

impl hal::digital::InputPin for SysfsPin {
impl embedded_hal::digital::InputPin for SysfsPin {
type Error = sysfs_gpio::Error;

fn try_is_high(&self) -> Result<bool, Self::Error> {
Expand Down
2 changes: 1 addition & 1 deletion src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use core::convert::Infallible;
use std::time::{Duration, Instant};

use hal::timer::{CountDown, Periodic};
use embedded_hal::timer::{CountDown, Periodic};

/// A periodic timer based on [`std::time::Instant`][instant], which is a
/// monotonically nondecreasing clock.
Expand Down