Skip to content

Commit

Permalink
Sample driver implementation/draft for rust-embedded/embedded-hal#54
Browse files Browse the repository at this point in the history
Quick refactor to fit the model described in
rust-embedded/embedded-hal#54 (comment)

Optional parasite mode for the OpenDrain implementation got dropped.
  • Loading branch information
kellerkindt committed Jul 12, 2018
1 parent e44cdf2 commit 9bdc2da
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 342 deletions.
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ readme = "README.md"

[lib]

[features]
default = []
embedded-opendrain = ["embedded-hal"]
embedded-spi = ["embedded-hal"]
linux-gpio = []

[dependencies]
byteorder = { version = "1", default-features = false }

[dependencies.embedded-hal]
features = ["unproven"]
version = "0.2.1"
optional = true
32 changes: 32 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

use super::ADDRESS_BYTES;

use core::fmt::Display;
use core::fmt::Formatter;

#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Device {
pub address: [u8; ADDRESS_BYTES as usize]
}

impl Device {
pub fn family_code(&self) -> u8 {
self.address[0]
}
}


impl Display for Device {
fn fmt(&self, f: &mut Formatter) -> ::core::fmt::Result {
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.address[0],
self.address[1],
self.address[2],
self.address[3],
self.address[4],
self.address[5],
self.address[6],
self.address[7],
)
}
}
114 changes: 114 additions & 0 deletions src/driver/embedded_opendrain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
extern crate embedded_hal as hal;

use self::hal::digital::OutputPin;
use self::hal::digital::InputPin;
use self::hal::blocking::delay::DelayUs;


use Error;
use Driver;
use BitDriver;


pub trait OpenDrainOutput: OutputPin + InputPin {}
impl<P: OutputPin + InputPin> OpenDrainOutput for P {}

pub struct BlockingOpenDrainByteDriver<'a> {
pin: &'a mut OpenDrainOutput,
delay: &'a mut DelayUs<u16>,
}

impl<'a> BlockingOpenDrainByteDriver<'a> {
pub fn new(pin: &'a mut OpenDrainOutput, delay: &'a mut DelayUs<u16>) -> BlockingOpenDrainByteDriver<'a> {
BlockingOpenDrainByteDriver {
pin,
delay,
}
}

fn set_input(&mut self) {
// nothing to do
self.pin.set_high()
}

fn set_output(&mut self) {
// nothing to do
}

fn write_low(&mut self) {
self.pin.set_low()
}

fn write_high(&mut self) {
self.pin.set_high()
}

fn read(&self) -> bool {
self.pin.is_high()
}

fn ensure_wire_high(&mut self) -> Result<(), Error> {
for _ in 0..125 {
if self.read_bit()? {
return Ok(());
}
self.delay.delay_us(2);
}
Err(Error::WireNotHigh)
}
}



impl<'a> Driver for BlockingOpenDrainByteDriver<'a> {
fn reset(&mut self) -> Result<bool, Error> {
// let mut cli = DisableInterrupts::new();
self.set_input();
// drop(cli);

self.ensure_wire_high()?;
// cli = DisableInterrupts::new();
self.write_low();
self.set_output();

// drop(cli);
self.delay.delay_us(480);
// cli = DisableInterrupts::new();
self.set_input();

let mut val = false;
for _ in 0..7 {
self.delay.delay_us(10);
val |= !self.read_bit()?;
}
// drop(cli);
self.delay.delay_us(410);
Ok(val)
}
}

impl<'a> BitDriver for BlockingOpenDrainByteDriver<'a> {
fn read_bit(&mut self) -> Result<bool, Error> {
// let cli = DisableInterrupts::new();
self.set_output();
self.write_low();
self.delay.delay_us(3);
self.set_input();
self.delay.delay_us(2); // was 10
let val = self.read();
// drop(cli);
self.delay.delay_us(61); // was 53
Ok(val)
}

fn write_bit(&mut self, high: bool) -> Result<(), Error> {
// let cli = DisableInterrupts::new();
self.write_low();
self.set_output();
self.delay.delay_us(if high {10} else {65});
self.write_high();
// drop(cli);
self.delay.delay_us(if high {55} else {5});
Ok(())
}
}
Empty file added src/driver/embedded_spi.rs
Empty file.
Empty file added src/driver/linux_gpio.rs
Empty file.
84 changes: 84 additions & 0 deletions src/driver/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

#[cfg(feature = "embedded-opendrain")] mod embedded_opendrain;
#[cfg(feature = "embedded-opendrain")] pub use self::embedded_opendrain::*;

#[cfg(feature = "embedded-spi")] mod embedded_spi;
#[cfg(feature = "embedded-spi")] pub use self::embedded_spi::*;

#[cfg(feature = "linux-gpio")] mod embedded_spi;
#[cfg(feature = "linux-gpio")] pub use self::embedded_spi::*;


use super::Error;

pub trait Driver {
/// Performs a reset and listens for a presence pulse
/// Returns Err(WireNotHigh) if the wire seems to be shortened,
/// Ok(true) if presence pulse has been received and Ok(false)
/// if no other device was detected but the wire seems to be ok
fn reset(&mut self) -> Result<bool, Error>;
}

pub trait BitDriver: Driver {
fn read_bit(&mut self) -> Result<bool, Error>;

fn write_bit(&mut self, data: bool) -> Result<(), Error>;
}

pub trait ByteDriver: Driver {
fn read_byte(&mut self) -> Result<u8, Error>;

fn read_bytes(&mut self, data: &mut [u8]) -> Result<(), Error> {
for byte in data.iter_mut() {
*byte = self.read_byte()?;
}
Ok(())
}

fn write_byte(&mut self, data: u8) -> Result<(), Error>;

fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> {
for byte in data {
self.write_byte(*byte)?;
}
Ok(())
}
}

impl<T: BitDriver> ByteDriver for T {
fn read_byte(&mut self) -> Result<u8, Error> {
fn to_bit(state: bool) -> u8 {
if state {
0x01
} else {
0x00
}
}
Ok(
to_bit(self.read_bit()?) << 7
| to_bit(self.read_bit()?) << 6
| to_bit(self.read_bit()?) << 5
| to_bit(self.read_bit()?) << 4
| to_bit(self.read_bit()?) << 3
| to_bit(self.read_bit()?) << 2
| to_bit(self.read_bit()?) << 1
| to_bit(self.read_bit()?)
)
}

fn write_byte(&mut self, data: u8) -> Result<(), Error> {
fn is_bit_set(byte: u8, n: u8) -> bool {
let flag = 0x01 << n;
byte & flag == flag
}
self.write_bit(is_bit_set(data, 7))?;
self.write_bit(is_bit_set(data, 6))?;
self.write_bit(is_bit_set(data, 5))?;
self.write_bit(is_bit_set(data, 4))?;
self.write_bit(is_bit_set(data, 3))?;
self.write_bit(is_bit_set(data, 2))?;
self.write_bit(is_bit_set(data, 1))?;
self.write_bit(is_bit_set(data, 0))?;
Ok(())
}
}
25 changes: 5 additions & 20 deletions src/ds18b20.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@

use byteorder::ByteOrder;
use byteorder::LittleEndian;
use hal::blocking::delay::DelayUs;

use Error;
use Device;
use Sensor;
use OneWire;
use ByteDriver;

pub const FAMILY_CODE : u8 = 0x28;

Expand Down Expand Up @@ -64,14 +63,14 @@ impl DS18B20 {
}
}

pub fn measure_temperature(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<MeasureResolution, Error> {
wire.reset_select_write_only(delay, &self.device, &[Command::Convert as u8])?;
pub fn measure_temperature<D: ByteDriver>(&self, wire: &mut OneWire<D>) -> Result<MeasureResolution, Error> {
wire.reset_select_write_only(&self.device, &[Command::Convert as u8])?;
Ok(self.resolution)
}

pub fn read_temperature(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<f32, Error> {
pub fn read_temperature<D: ByteDriver>(&self, wire: &mut OneWire<D>) -> Result<f32, Error> {
let mut scratchpad = [0u8; 9];
wire.reset_select_write_read(delay, &self.device, &[Command::ReadScratchpad as u8], &mut scratchpad[..])?;
wire.reset_select_write_read(&self.device, &[Command::ReadScratchpad as u8], &mut scratchpad[..])?;
super::ensure_correct_rcr8(&self.device,&scratchpad[..8], scratchpad[8])?;
Ok(DS18B20::read_temperature_from_scratchpad(&scratchpad))
}
Expand All @@ -81,18 +80,4 @@ impl DS18B20 {
let temp_f32 = temp_u16 as i16 as f32 / 16_f32;
temp_f32
}
}

impl Sensor for DS18B20 {
fn family_code() -> u8 {
FAMILY_CODE
}

fn start_measurement(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<u16, Error> {
Ok(self.measure_temperature(wire, delay)?.time_ms())
}

fn read_measurement(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<f32, Error> {
self.read_temperature(wire, delay)
}
}
Loading

0 comments on commit 9bdc2da

Please sign in to comment.