Skip to content

Use the embedded-hal::digital::v2::OutputPin traits #8

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 2 commits into from
Jun 10, 2019
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ branch = "master"
repository = "jamwaffles/sh1106"

[dependencies]
embedded-hal = "0.2.2"
embedded-hal = "0.2.3"

[dependencies.embedded-graphics]
optional = true
Expand Down
27 changes: 17 additions & 10 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
//! ```

use hal;
use hal::digital::OutputPin;
use hal::digital::v2::OutputPin;

use crate::displayrotation::DisplayRotation;
use crate::displaysize::DisplaySize;
Expand Down Expand Up @@ -77,9 +77,9 @@ impl Builder {
}
}

impl<CS> Builder<CS>
impl<CS, PinE> Builder<CS>
where
CS: OutputPin,
CS: OutputPin<Error = PinE>,
{
/// Set the size of the display. Supported sizes are defined by [DisplaySize].
pub fn with_size(self, display_size: DisplaySize) -> Self {
Expand Down Expand Up @@ -116,9 +116,9 @@ where
}

/// Finish the builder and use I2C to communicate with the display
pub fn connect_i2c<I2C>(self, i2c: I2C) -> DisplayMode<RawMode<I2cInterface<I2C>>>
pub fn connect_i2c<I2C, CommE>(self, i2c: I2C) -> DisplayMode<RawMode<I2cInterface<I2C>>>
where
I2C: hal::blocking::i2c::Write,
I2C: hal::blocking::i2c::Write<Error = CommE>,
{
let properties = DisplayProperties::new(
I2cInterface::new(i2c, self.i2c_addr),
Expand All @@ -129,14 +129,16 @@ where
}

/// Finish the builder and use SPI to communicate with the display
pub fn connect_spi<SPI, DC>(
pub fn connect_spi<SPI, DC, CommE>(
self,
spi: SPI,
dc: DC,
) -> DisplayMode<RawMode<SpiInterface<SPI, DC, CS>>>
where
SPI: hal::blocking::spi::Transfer<u8> + hal::blocking::spi::Write<u8>,
DC: OutputPin,
SPI: hal::blocking::spi::Transfer<u8, Error = CommE>
+ hal::blocking::spi::Write<u8, Error = CommE>,
DC: OutputPin<Error = PinE>,
CS: OutputPin<Error = PinE>,
{
let properties = DisplayProperties::new(
SpiInterface::new(spi, dc, self.spi_cs),
Expand All @@ -152,6 +154,11 @@ where
pub struct NoOutputPin;

impl OutputPin for NoOutputPin {
fn set_low(&mut self) {}
fn set_high(&mut self) {}
type Error = ();
fn set_low(&mut self) -> Result<(), ()> {
Ok(())
}
fn set_high(&mut self) -> Result<(), ()> {
Ok(())
}
}
6 changes: 2 additions & 4 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub enum Command {

impl Command {
/// Send command to sh1106
pub fn send<DI>(self, iface: &mut DI) -> Result<(), ()>
pub fn send<DI>(self, iface: &mut DI) -> Result<(), DI::Error>
where
DI: DisplayInterface,
{
Expand Down Expand Up @@ -83,9 +83,7 @@ impl Command {
};

// Send command over the interface
iface.send_commands(&data[0..len])?;

Ok(())
iface.send_commands(&data[0..len])
}
}

Expand Down
23 changes: 14 additions & 9 deletions src/interface/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use hal;

use super::DisplayInterface;
use crate::command::Page;
use crate::Error;

// TODO: Add to prelude
/// sh1106 I2C communication interface
Expand All @@ -22,23 +23,27 @@ where
}
}

impl<I2C> DisplayInterface for I2cInterface<I2C>
impl<I2C, CommE> DisplayInterface for I2cInterface<I2C>
where
I2C: hal::blocking::i2c::Write,
I2C: hal::blocking::i2c::Write<Error = CommE>,
{
fn send_commands(&mut self, cmds: &[u8]) -> Result<(), ()> {
type Error = Error<CommE, ()>;

fn init(&mut self) -> Result<(), Self::Error> {
Ok(())
}

fn send_commands(&mut self, cmds: &[u8]) -> Result<(), Self::Error> {
// Copy over given commands to new aray to prefix with command identifier
let mut writebuf: [u8; 8] = [0; 8];
writebuf[1..=cmds.len()].copy_from_slice(&cmds);

self.i2c
.write(self.addr, &writebuf[..=cmds.len()])
.map_err(|_| ())?;

Ok(())
.map_err(Error::Comm)
}

fn send_data(&mut self, buf: &[u8]) -> Result<(), ()> {
fn send_data(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
// Display is always 128px wide
const CHUNKLEN: usize = 128;

Expand Down Expand Up @@ -70,9 +75,9 @@ where
0x10, // Upper column address (always zero, base is 10h)
],
)
.map_err(|_| ())?;
.map_err(Error::Comm)?;

self.i2c.write(self.addr, &writebuf).map_err(|_| ())?;
self.i2c.write(self.addr, &writebuf).map_err(Error::Comm)?;

page += 1;
}
Expand Down
9 changes: 7 additions & 2 deletions src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,15 @@ pub mod spi;

/// A method of communicating with sh1106
pub trait DisplayInterface {
/// Interface error type
type Error;

/// Initialize device.
fn init(&mut self) -> Result<(), Self::Error>;
/// Send a batch of up to 8 commands to display.
fn send_commands(&mut self, cmd: &[u8]) -> Result<(), ()>;
fn send_commands(&mut self, cmd: &[u8]) -> Result<(), Self::Error>;
/// Send data to display.
fn send_data(&mut self, buf: &[u8]) -> Result<(), ()>;
fn send_data(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
}

pub use self::i2c::I2cInterface;
Expand Down
53 changes: 27 additions & 26 deletions src/interface/spi.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! sh1106 SPI interface

use hal;
use hal::digital::OutputPin;
use hal::digital::v2::OutputPin;

use super::DisplayInterface;
use crate::Error;

/// SPI display interface.
///
Expand All @@ -14,48 +15,48 @@ pub struct SpiInterface<SPI, DC, CS> {
cs: CS,
}

impl<SPI, DC, CS> SpiInterface<SPI, DC, CS>
impl<SPI, DC, CS, CommE, PinE> SpiInterface<SPI, DC, CS>
where
SPI: hal::blocking::spi::Write<u8>,
DC: OutputPin,
CS: OutputPin,
SPI: hal::blocking::spi::Write<u8, Error = CommE>,
DC: OutputPin<Error = PinE>,
CS: OutputPin<Error = PinE>,
{
/// Create new SPI interface for communciation with sh1106
pub fn new(spi: SPI, dc: DC, mut cs: CS) -> Self {
cs.set_high();

pub fn new(spi: SPI, dc: DC, cs: CS) -> Self {
Self { spi, dc, cs }
}
}

impl<SPI, DC, CS> DisplayInterface for SpiInterface<SPI, DC, CS>
impl<SPI, DC, CS, CommE, PinE> DisplayInterface for SpiInterface<SPI, DC, CS>
where
SPI: hal::blocking::spi::Write<u8>,
DC: OutputPin,
CS: OutputPin,
SPI: hal::blocking::spi::Write<u8, Error = CommE>,
DC: OutputPin<Error = PinE>,
CS: OutputPin<Error = PinE>,
{
fn send_commands(&mut self, cmds: &[u8]) -> Result<(), ()> {
self.cs.set_low();
self.dc.set_low();
type Error = Error<CommE, PinE>;

fn init(&mut self) -> Result<(), Self::Error> {
self.cs.set_high().map_err(Error::Pin)
}

self.spi.write(&cmds).map_err(|_| ())?;
fn send_commands(&mut self, cmds: &[u8]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(Error::Pin)?;
self.dc.set_low().map_err(Error::Pin)?;

self.dc.set_high();
self.cs.set_high();
self.spi.write(&cmds).map_err(Error::Comm)?;

Ok(())
self.dc.set_high().map_err(Error::Pin)?;
self.cs.set_high().map_err(Error::Pin)
}

fn send_data(&mut self, buf: &[u8]) -> Result<(), ()> {
self.cs.set_low();
fn send_data(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(Error::Pin)?;

// 1 = data, 0 = command
self.dc.set_high();

self.spi.write(&buf).map_err(|_| ())?;
self.dc.set_high().map_err(Error::Pin)?;

self.cs.set_high();
self.spi.write(&buf).map_err(Error::Comm)?;

Ok(())
self.cs.set_high().map_err(Error::Pin)
}
}
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]

/// Errors in this crate
#[derive(Debug)]
pub enum Error<CommE, PinE> {
/// Communication error
Comm(CommE),
/// Pin setting error
Pin(PinE),
}

extern crate embedded_hal as hal;

pub mod builder;
Expand Down
26 changes: 15 additions & 11 deletions src/mode/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
//! ```

use hal::blocking::delay::DelayMs;
use hal::digital::OutputPin;
use hal::digital::v2::OutputPin;

use crate::displayrotation::DisplayRotation;
use crate::displaysize::DisplaySize;
use crate::interface::DisplayInterface;
use crate::mode::displaymode::DisplayModeTrait;
use crate::properties::DisplayProperties;
use crate::Error;

const BUFFER_SIZE: usize = 132 * 64 / 8;

Expand Down Expand Up @@ -65,20 +66,24 @@ where

/// Reset display
// TODO: Move to a more appropriate place
pub fn reset<RST, DELAY>(&mut self, rst: &mut RST, delay: &mut DELAY)
pub fn reset<RST, DELAY, PinE>(
&mut self,
rst: &mut RST,
delay: &mut DELAY,
) -> Result<(), Error<(), PinE>>
where
RST: OutputPin,
RST: OutputPin<Error = PinE>,
DELAY: DelayMs<u8>,
{
rst.set_high();
rst.set_high().map_err(Error::Pin)?;
delay.delay_ms(1);
rst.set_low();
rst.set_low().map_err(Error::Pin)?;
delay.delay_ms(10);
rst.set_high();
rst.set_high().map_err(Error::Pin)
}

/// Write out data to display
pub fn flush(&mut self) -> Result<(), ()> {
pub fn flush(&mut self) -> Result<(), DI::Error> {
let display_size = self.properties.get_size();

// Ensure the display buffer is at the origin of the display before we send the full frame
Expand Down Expand Up @@ -147,9 +152,8 @@ where

/// Display is set up in column mode, i.e. a byte walks down a column of 8 pixels from
/// column 0 on the left, to column _n_ on the right
pub fn init(&mut self) -> Result<(), ()> {
self.properties.init_column_mode()?;
Ok(())
pub fn init(&mut self) -> Result<(), DI::Error> {
self.properties.init_column_mode()
}

/// Get display dimensions, taking into account the current rotation of the display
Expand All @@ -158,7 +162,7 @@ where
}

/// Set the display rotation
pub fn set_rotation(&mut self, rot: DisplayRotation) -> Result<(), ()> {
pub fn set_rotation(&mut self, rot: DisplayRotation) -> Result<(), DI::Error> {
self.properties.set_rotation(rot)
}
}
Expand Down
Loading