Skip to content

Use the embedded-hal::digital::v2::OutputPin #83

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 14, 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/ssd1306"

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

[dev-dependencies.stm32f1xx-hal]
version = "0.2.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn main() -> ! {

let mut disp: GraphicsMode<_> = Builder::new().connect_spi(spi, dc).into();

disp.reset(&mut rst, &mut delay);
disp.reset(&mut rst, &mut delay).unwrap();
disp.init().unwrap();
disp.flush().unwrap();

Expand Down
2 changes: 1 addition & 1 deletion examples/pixelsquare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn main() -> ! {

let mut disp: GraphicsMode<_> = Builder::new().connect_spi(spi, dc).into();

disp.reset(&mut rst, &mut delay);
disp.reset(&mut rst, &mut delay).unwrap();
disp.init().unwrap();
disp.flush().unwrap();

Expand Down
13 changes: 7 additions & 6 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 @@ -96,9 +96,9 @@ impl Builder {
}

/// 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 @@ -109,14 +109,15 @@ impl Builder {
}

/// Finish the builder and use SPI to communicate with the display
pub fn connect_spi<SPI, DC>(
pub fn connect_spi<SPI, DC, CommE, PinE>(
&self,
spi: SPI,
dc: DC,
) -> DisplayMode<RawMode<SpiInterface<SPI, DC>>>
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>,
{
let properties =
DisplayProperties::new(SpiInterface::new(spi, dc), self.display_size, self.rotation);
Expand Down
6 changes: 2 additions & 4 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub enum Command {

impl Command {
/// Send command to SSD1306
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 @@ -156,9 +156,7 @@ impl Command {
};

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

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

Expand Down
21 changes: 11 additions & 10 deletions src/interface/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use hal;

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

// TODO: Add to prelude
/// SSD1306 I2C communication interface
Expand All @@ -11,33 +12,33 @@ pub struct I2cInterface<I2C> {
addr: u8,
}

impl<I2C> I2cInterface<I2C>
impl<I2C, CommE> I2cInterface<I2C>
where
I2C: hal::blocking::i2c::Write,
I2C: hal::blocking::i2c::Write<Error = CommE>,
{
/// Create new SSD1306 I2C interface
pub fn new(i2c: I2C, addr: u8) -> Self {
Self { i2c, addr }
}
}

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 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[0..cmds.len()]);

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> {
// Noop if the data buffer is empty
if buf.is_empty() {
return Ok(());
Expand All @@ -57,7 +58,7 @@ where

self.i2c
.write(self.addr, &writebuf[..=chunklen])
.map_err(|_| ())?;
.map_err(Error::Comm)?;
}

Ok(())
Expand Down
6 changes: 4 additions & 2 deletions src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ pub mod spi;

/// A method of communicating with SSD1306
pub trait DisplayInterface {
/// Interface error type
type 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
33 changes: 16 additions & 17 deletions src/interface/spi.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! SSD1306 SPI interface

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

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

// TODO: Add to prelude
/// SPI display interface.
Expand All @@ -14,38 +15,36 @@ pub struct SpiInterface<SPI, DC> {
dc: DC,
}

impl<SPI, DC> SpiInterface<SPI, DC>
impl<SPI, DC, CommE, PinE> SpiInterface<SPI, DC>
where
SPI: hal::blocking::spi::Write<u8>,
DC: OutputPin,
SPI: hal::blocking::spi::Write<u8, Error = CommE>,
DC: OutputPin<Error = PinE>,
{
/// Create new SPI interface for communciation with SSD1306
pub fn new(spi: SPI, dc: DC) -> Self {
Self { spi, dc }
}
}

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

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

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

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

fn send_data(&mut self, buf: &[u8]) -> Result<(), ()> {
fn send_data(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
// 1 = data, 0 = command
self.dc.set_high();
self.dc.set_high().map_err(Error::Pin)?;

self.spi.write(&buf).map_err(|_| ())?;

Ok(())
self.spi.write(&buf).map_err(Error::Comm)
}
}
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,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;

// TODO: Add to prelude
/// Graphics mode handler
Expand Down Expand Up @@ -63,20 +64,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 @@ -144,9 +149,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 @@ -155,7 +159,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
31 changes: 17 additions & 14 deletions src/mode/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ use crate::displaysize::DisplaySize;
use crate::interface::DisplayInterface;
use crate::mode::displaymode::DisplayModeTrait;
use crate::properties::DisplayProperties;
use crate::Error;
use core::fmt;
use hal::blocking::delay::DelayMs;
use hal::digital::OutputPin;
use hal::digital::v2::OutputPin;

/// A trait to convert from a character to 8x8 bitmap
pub trait CharacterBitmap<T> {
Expand Down Expand Up @@ -165,7 +166,7 @@ where
DI: DisplayInterface,
{
/// Clear the display
pub fn clear(&mut self) -> Result<(), ()> {
pub fn clear(&mut self) -> Result<(), DI::Error> {
let display_size = self.properties.get_size();

let numchars = match display_size {
Expand All @@ -187,16 +188,20 @@ where
}

/// Reset display
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. This is a noop in terminal mode.
Expand All @@ -205,24 +210,22 @@ where
}

/// Print a character to the display
pub fn print_char<T>(&mut self, c: T) -> Result<(), ()>
pub fn print_char<T>(&mut self, c: T) -> Result<(), DI::Error>
where
TerminalMode<DI>: CharacterBitmap<T>,
{
// Send the pixel data to the display
self.properties.draw(&Self::to_bitmap(c))?;
Ok(())
self.properties.draw(&Self::to_bitmap(c))
}

/// Initialise the display in column mode (i.e. a byte walks down a column of 8 pixels) with
/// column 0 on the left and column _(display_width - 1)_ 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()
}

/// 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