Skip to content
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

Type-level display size #125

Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

### Changed

- **(breaking)** [#125](https://github.com/jamwaffles/ssd1306/pull/125) Redesigned display size handling.
- **(breaking)** [#126](https://github.com/jamwaffles/ssd1306/pull/126) Moved `reset` method to `DisplayModeTrait`. If the prelude is not used, add either `use ssd1306::prelude::*` or `ssd1306::mode::displaymode::DisplayModeTrait` to your imports.
- **(breaking)** [#119](https://github.com/jamwaffles/ssd1306/pull/119) Remove `DisplayMode` and `RawMode`
- [#120](https://github.com/jamwaffles/ssd1306/pull/120) Update to v0.4 [`display-interface`](https://crates.io/crates/display-interface)
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ embedded-hal = "0.2.3"
display-interface = "0.4"
display-interface-i2c = "0.4"
display-interface-spi = "0.4"
generic-array = "0.14.2"

[dependencies.embedded-graphics]
optional = true
Expand Down
4 changes: 2 additions & 2 deletions examples/graphics_i2c_128x32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ fn main() -> ! {
);

let interface = I2CDIBuilder::new().init(i2c);
let mut disp: GraphicsMode<_> = Builder::new()
.size(DisplaySize::Display128x32)
let mut disp: GraphicsMode<_, _> = Builder::new()
.size(DisplaySize128x32)
.connect(interface)
.into();
disp.init().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions examples/graphics_i2c_72x40.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ fn main() -> ! {
);

let interface = I2CDIBuilder::new().init(i2c);
let mut disp: GraphicsMode<_> = Builder::new()
.size(DisplaySize::Display72x40)
let mut disp: GraphicsMode<_, _> = Builder::new()
.size(DisplaySize72x40)
.connect(interface)
.into();
disp.init().unwrap();
Expand Down
49 changes: 35 additions & 14 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,24 @@
//! use ssd1306::{prelude::*, Builder, I2CDIBuilder};
//!
//! let interface = I2CDIBuilder::new().init(i2c);
//! Builder::new()
//! let di: DisplayProperties<_> = Builder::new()
//! .with_rotation(DisplayRotation::Rotate180)
//! .size(DisplaySize::Display128x32)
//! .connect(interface);
//! ```
//!
//! The builder defaults to a display size of 128 x 64px. To use a display with a different size,
//! call the [`size`](#method.size) method. Supported sizes can be found in the
//! [`displaysize`](../displaysize/index.html) module or in the [prelude](../prelude/index.html).
//!
//! ```rust
//! # use ssd1306::test_helpers::{PinStub, I2cStub};
//! # let i2c = I2cStub;
//! use ssd1306::{prelude::*, Builder, I2CDIBuilder};
//!
//! let interface = I2CDIBuilder::new().init(i2c);
//! let di: DisplayProperties<_, _> = Builder::new()
//! .with_rotation(DisplayRotation::Rotate180)
//! .size(DisplaySize128x32)
//! .connect(interface);
//! ```
//!
Expand All @@ -58,14 +73,15 @@

use display_interface::WriteOnlyDataCommand;

use crate::{
displayrotation::DisplayRotation, displaysize::DisplaySize, properties::DisplayProperties,
};
use crate::{displayrotation::DisplayRotation, displaysize::*, properties::DisplayProperties};

/// Builder struct. Driver options and interface are set using its methods.
#[derive(Clone, Copy)]
pub struct Builder {
display_size: DisplaySize,
pub struct Builder<DSIZE = DisplaySize128x64>
where
DSIZE: DisplaySize,
{
size: DSIZE,
rotation: DisplayRotation,
}

Expand All @@ -79,16 +95,21 @@ impl Builder {
/// Create new builder with a default size of 128 x 64 pixels and no rotation.
pub fn new() -> Self {
Self {
display_size: DisplaySize::Display128x64,
size: DisplaySize128x64,
rotation: DisplayRotation::Rotate0,
}
}
}

impl<DSIZE> Builder<DSIZE>
where
DSIZE: DisplaySize,
{
/// Set the size of the display. Supported sizes are defined by [DisplaySize].
pub fn size(self, display_size: DisplaySize) -> Self {
Self {
display_size,
..self
pub fn size<S: DisplaySize>(self, size: S) -> Builder<S> {
Builder {
size,
rotation: self.rotation,
}
}

Expand All @@ -102,11 +123,11 @@ impl Builder {
/// Finish the builder and use some interface communicate with the display
///
/// This method consumes the builder and must come last in the method call chain
pub fn connect<I>(self, interface: I) -> DisplayProperties<I>
pub fn connect<I>(self, interface: I) -> DisplayProperties<I, DSIZE>
where
I: WriteOnlyDataCommand,
{
DisplayProperties::new(interface, self.display_size, self.rotation)
DisplayProperties::new(interface, self.size, self.rotation)
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/command.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Display commands.

// Shamefully taken from https://github.com/EdgewaterDevelopment/rust-ssd1306

use display_interface::{DataFormat::U8, DisplayError, WriteOnlyDataCommand};

/// SSD1306 Commands

/// Commands
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
pub enum Command {
/// Set contrast. Higher number is higher contrast. Default = 0x7F
Expand Down
124 changes: 99 additions & 25 deletions src/displaysize.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,105 @@
//! Display size

// TODO: Add to prelude
/// Display size enumeration
#[derive(Clone, Copy)]
pub enum DisplaySize {
/// 128 by 64 pixels
Display128x64,
/// 128 by 32 pixels
Display128x32,
/// 96 by 16 pixels
Display96x16,
/// 70 by 42 pixels
Display72x40,
/// 64 by 48 pixels
Display64x48,
use super::command::Command;
use display_interface::{DisplayError, WriteOnlyDataCommand};
use generic_array::{
typenum::{U1024, U192, U360, U384, U512},
ArrayLength,
};

/// Display information
///
/// This trait describes information related to a particular display.
/// This includes resolution, offset and framebuffer size.
pub trait DisplaySize {
/// Width in pixels
const WIDTH: u8;

/// Height in pixels
const HEIGHT: u8;

/// Horizontal offset in pixels
const OFFSETX: u8 = 0;

/// Vertical offset in pixels
const OFFSETY: u8 = 0;

/// Size of framebuffer. Because the display is monocrome, this is
/// width * height / 8
type BufferSize: ArrayLength<u8>;

/// Send resolution-dependent configuration to the display
///
/// See [`Command::ComPinConfig`](../command/enum.Command.html#variant.ComPinConfig)
/// for more information
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError>;
}

impl DisplaySize {
/// Get integral dimensions from DisplaySize
// TODO: Use whatever vec2 impl I decide to use here
pub fn dimensions(self) -> (u8, u8) {
match self {
DisplaySize::Display128x64 => (128, 64),
DisplaySize::Display128x32 => (128, 32),
DisplaySize::Display96x16 => (96, 16),
DisplaySize::Display72x40 => (72, 40),
DisplaySize::Display64x48 => (64, 48),
}
/// Size information for the common 128x64 variants
#[derive(Debug, Copy, Clone)]
pub struct DisplaySize128x64;
impl DisplaySize for DisplaySize128x64 {
const WIDTH: u8 = 128;
const HEIGHT: u8 = 64;
type BufferSize = U1024;

fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
Command::ComPinConfig(true, false).send(iface)
}
}

/// Size information for the common 128x32 variants
#[derive(Debug, Copy, Clone)]
pub struct DisplaySize128x32;
impl DisplaySize for DisplaySize128x32 {
const WIDTH: u8 = 128;
const HEIGHT: u8 = 32;
type BufferSize = U512;

fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
Command::ComPinConfig(false, false).send(iface)
}
}

/// Size information for the common 96x16 variants
#[derive(Debug, Copy, Clone)]
pub struct DisplaySize96x16;
impl DisplaySize for DisplaySize96x16 {
const WIDTH: u8 = 96;
const HEIGHT: u8 = 16;
type BufferSize = U192;

fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
Command::ComPinConfig(false, false).send(iface)
}
}

/// Size information for the common 72x40 variants
#[derive(Debug, Copy, Clone)]
pub struct DisplaySize72x40;
impl DisplaySize for DisplaySize72x40 {
const WIDTH: u8 = 72;
const HEIGHT: u8 = 40;
const OFFSETX: u8 = 28;
const OFFSETY: u8 = 0;
type BufferSize = U360;

fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
Command::ComPinConfig(true, false).send(iface)
}
}

/// Size information for the common 64x48 variants
#[derive(Debug, Copy, Clone)]
pub struct DisplaySize64x48;
impl DisplaySize for DisplaySize64x48 {
const WIDTH: u8 = 64;
const HEIGHT: u8 = 48;
const OFFSETX: u8 = 32;
const OFFSETY: u8 = 0;
type BufferSize = U384;

fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
Command::ComPinConfig(true, false).send(iface)
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ extern crate embedded_hal as hal;

pub mod brightness;
pub mod builder;
mod command;
pub mod command;
pub mod displayrotation;
mod displaysize;
pub mod displaysize;
pub mod mode;
pub mod prelude;
pub mod properties;
Expand Down
6 changes: 3 additions & 3 deletions src/mode/displaymode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use crate::Error;
use hal::{blocking::delay::DelayMs, digital::v2::OutputPin};

/// Trait with core functionality for display mode switching
pub trait DisplayModeTrait<DI>: Sized {
pub trait DisplayModeTrait<DI, DSIZE>: Sized {
/// Allocate all required data and initialise display for mode
fn new(properties: DisplayProperties<DI>) -> Self;
fn new(properties: DisplayProperties<DI, DSIZE>) -> Self;

/// Deconstruct object and retrieve DisplayProperties
fn into_properties(self) -> DisplayProperties<DI>;
fn into_properties(self) -> DisplayProperties<DI, DSIZE>;

/// Release display interface
fn release(self) -> DI {
Expand Down
Loading