Skip to content

Commit 4d97c1e

Browse files
bugadaniDániel Bugajamwaffles
authored
Type-level display size (#125)
* Sketch up type-level display size * Use display buffers with only the necessary size * Run cargo fmt * Make the module public * Add defaults Try to at least be backwards compatible when the defaults are used * Implemented suggested changes * Command must be public to allow external implementations of DisplaySize * Docs to make CI happy * Run cargo fmt * Fix inference related errors, add display sizes to prelude * Fix formatting * Fix examples in doc comments * Looks like we need to be explicit with the types * Modify configuration to send the command instead of just constructing it This will align better with rotation where at least two commands must be transmitted for configuration * Cleanup * Remove outdated todo * No glob reexport * Add note about second type param, add properties to prelude * Add changelog entry * Fix resetting the dirty drawing area coordinates * Apply suggestions from code review Co-authored-by: James Waples <[email protected]> Co-authored-by: Dániel Buga <[email protected]> Co-authored-by: James Waples <[email protected]>
1 parent ec0d649 commit 4d97c1e

13 files changed

+250
-150
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
### Changed
1515

16+
- **(breaking)** [#125](https://github.com/jamwaffles/ssd1306/pull/125) Redesigned display size handling.
1617
- **(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.
1718
- **(breaking)** [#119](https://github.com/jamwaffles/ssd1306/pull/119) Remove `DisplayMode` and `RawMode`
1819
- [#120](https://github.com/jamwaffles/ssd1306/pull/120) Update to v0.4 [`display-interface`](https://crates.io/crates/display-interface)

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ embedded-hal = "0.2.3"
2222
display-interface = "0.4"
2323
display-interface-i2c = "0.4"
2424
display-interface-spi = "0.4"
25+
generic-array = "0.14.2"
2526

2627
[dependencies.embedded-graphics]
2728
optional = true

examples/graphics_i2c_128x32.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ fn main() -> ! {
6565
);
6666

6767
let interface = I2CDIBuilder::new().init(i2c);
68-
let mut disp: GraphicsMode<_> = Builder::new()
69-
.size(DisplaySize::Display128x32)
68+
let mut disp: GraphicsMode<_, _> = Builder::new()
69+
.size(DisplaySize128x32)
7070
.connect(interface)
7171
.into();
7272
disp.init().unwrap();

examples/graphics_i2c_72x40.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ fn main() -> ! {
6565
);
6666

6767
let interface = I2CDIBuilder::new().init(i2c);
68-
let mut disp: GraphicsMode<_> = Builder::new()
69-
.size(DisplaySize::Display72x40)
68+
let mut disp: GraphicsMode<_, _> = Builder::new()
69+
.size(DisplaySize72x40)
7070
.connect(interface)
7171
.into();
7272
disp.init().unwrap();

src/builder.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,24 @@
3131
//! use ssd1306::{prelude::*, Builder, I2CDIBuilder};
3232
//!
3333
//! let interface = I2CDIBuilder::new().init(i2c);
34-
//! Builder::new()
34+
//! let di: DisplayProperties<_> = Builder::new()
3535
//! .with_rotation(DisplayRotation::Rotate180)
36-
//! .size(DisplaySize::Display128x32)
36+
//! .connect(interface);
37+
//! ```
38+
//!
39+
//! The builder defaults to a display size of 128 x 64px. To use a display with a different size,
40+
//! call the [`size`](#method.size) method. Supported sizes can be found in the
41+
//! [`displaysize`](../displaysize/index.html) module or in the [prelude](../prelude/index.html).
42+
//!
43+
//! ```rust
44+
//! # use ssd1306::test_helpers::{PinStub, I2cStub};
45+
//! # let i2c = I2cStub;
46+
//! use ssd1306::{prelude::*, Builder, I2CDIBuilder};
47+
//!
48+
//! let interface = I2CDIBuilder::new().init(i2c);
49+
//! let di: DisplayProperties<_, _> = Builder::new()
50+
//! .with_rotation(DisplayRotation::Rotate180)
51+
//! .size(DisplaySize128x32)
3752
//! .connect(interface);
3853
//! ```
3954
//!
@@ -58,14 +73,15 @@
5873
5974
use display_interface::WriteOnlyDataCommand;
6075

61-
use crate::{
62-
displayrotation::DisplayRotation, displaysize::DisplaySize, properties::DisplayProperties,
63-
};
76+
use crate::{displayrotation::DisplayRotation, displaysize::*, properties::DisplayProperties};
6477

6578
/// Builder struct. Driver options and interface are set using its methods.
6679
#[derive(Clone, Copy)]
67-
pub struct Builder {
68-
display_size: DisplaySize,
80+
pub struct Builder<DSIZE = DisplaySize128x64>
81+
where
82+
DSIZE: DisplaySize,
83+
{
84+
size: DSIZE,
6985
rotation: DisplayRotation,
7086
}
7187

@@ -79,16 +95,21 @@ impl Builder {
7995
/// Create new builder with a default size of 128 x 64 pixels and no rotation.
8096
pub fn new() -> Self {
8197
Self {
82-
display_size: DisplaySize::Display128x64,
98+
size: DisplaySize128x64,
8399
rotation: DisplayRotation::Rotate0,
84100
}
85101
}
102+
}
86103

104+
impl<DSIZE> Builder<DSIZE>
105+
where
106+
DSIZE: DisplaySize,
107+
{
87108
/// Set the size of the display. Supported sizes are defined by [DisplaySize].
88-
pub fn size(self, display_size: DisplaySize) -> Self {
89-
Self {
90-
display_size,
91-
..self
109+
pub fn size<S: DisplaySize>(self, size: S) -> Builder<S> {
110+
Builder {
111+
size,
112+
rotation: self.rotation,
92113
}
93114
}
94115

@@ -102,11 +123,11 @@ impl Builder {
102123
/// Finish the builder and use some interface communicate with the display
103124
///
104125
/// This method consumes the builder and must come last in the method call chain
105-
pub fn connect<I>(self, interface: I) -> DisplayProperties<I>
126+
pub fn connect<I>(self, interface: I) -> DisplayProperties<I, DSIZE>
106127
where
107128
I: WriteOnlyDataCommand,
108129
{
109-
DisplayProperties::new(interface, self.display_size, self.rotation)
130+
DisplayProperties::new(interface, self.size, self.rotation)
110131
}
111132
}
112133

src/command.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
//! Display commands.
2+
13
// Shamefully taken from https://github.com/EdgewaterDevelopment/rust-ssd1306
24

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

57
/// SSD1306 Commands
68
79
/// Commands
8-
#[derive(Debug)]
10+
#[derive(Debug, Copy, Clone)]
911
#[allow(dead_code)]
1012
pub enum Command {
1113
/// Set contrast. Higher number is higher contrast. Default = 0x7F

src/displaysize.rs

Lines changed: 99 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,105 @@
11
//! Display size
22
3-
// TODO: Add to prelude
4-
/// Display size enumeration
5-
#[derive(Clone, Copy)]
6-
pub enum DisplaySize {
7-
/// 128 by 64 pixels
8-
Display128x64,
9-
/// 128 by 32 pixels
10-
Display128x32,
11-
/// 96 by 16 pixels
12-
Display96x16,
13-
/// 70 by 42 pixels
14-
Display72x40,
15-
/// 64 by 48 pixels
16-
Display64x48,
3+
use super::command::Command;
4+
use display_interface::{DisplayError, WriteOnlyDataCommand};
5+
use generic_array::{
6+
typenum::{U1024, U192, U360, U384, U512},
7+
ArrayLength,
8+
};
9+
10+
/// Display information
11+
///
12+
/// This trait describes information related to a particular display.
13+
/// This includes resolution, offset and framebuffer size.
14+
pub trait DisplaySize {
15+
/// Width in pixels
16+
const WIDTH: u8;
17+
18+
/// Height in pixels
19+
const HEIGHT: u8;
20+
21+
/// Horizontal offset in pixels
22+
const OFFSETX: u8 = 0;
23+
24+
/// Vertical offset in pixels
25+
const OFFSETY: u8 = 0;
26+
27+
/// Size of framebuffer. Because the display is monocrome, this is
28+
/// width * height / 8
29+
type BufferSize: ArrayLength<u8>;
30+
31+
/// Send resolution-dependent configuration to the display
32+
///
33+
/// See [`Command::ComPinConfig`](../command/enum.Command.html#variant.ComPinConfig)
34+
/// for more information
35+
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError>;
1736
}
1837

19-
impl DisplaySize {
20-
/// Get integral dimensions from DisplaySize
21-
// TODO: Use whatever vec2 impl I decide to use here
22-
pub fn dimensions(self) -> (u8, u8) {
23-
match self {
24-
DisplaySize::Display128x64 => (128, 64),
25-
DisplaySize::Display128x32 => (128, 32),
26-
DisplaySize::Display96x16 => (96, 16),
27-
DisplaySize::Display72x40 => (72, 40),
28-
DisplaySize::Display64x48 => (64, 48),
29-
}
38+
/// Size information for the common 128x64 variants
39+
#[derive(Debug, Copy, Clone)]
40+
pub struct DisplaySize128x64;
41+
impl DisplaySize for DisplaySize128x64 {
42+
const WIDTH: u8 = 128;
43+
const HEIGHT: u8 = 64;
44+
type BufferSize = U1024;
45+
46+
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
47+
Command::ComPinConfig(true, false).send(iface)
48+
}
49+
}
50+
51+
/// Size information for the common 128x32 variants
52+
#[derive(Debug, Copy, Clone)]
53+
pub struct DisplaySize128x32;
54+
impl DisplaySize for DisplaySize128x32 {
55+
const WIDTH: u8 = 128;
56+
const HEIGHT: u8 = 32;
57+
type BufferSize = U512;
58+
59+
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
60+
Command::ComPinConfig(false, false).send(iface)
61+
}
62+
}
63+
64+
/// Size information for the common 96x16 variants
65+
#[derive(Debug, Copy, Clone)]
66+
pub struct DisplaySize96x16;
67+
impl DisplaySize for DisplaySize96x16 {
68+
const WIDTH: u8 = 96;
69+
const HEIGHT: u8 = 16;
70+
type BufferSize = U192;
71+
72+
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
73+
Command::ComPinConfig(false, false).send(iface)
74+
}
75+
}
76+
77+
/// Size information for the common 72x40 variants
78+
#[derive(Debug, Copy, Clone)]
79+
pub struct DisplaySize72x40;
80+
impl DisplaySize for DisplaySize72x40 {
81+
const WIDTH: u8 = 72;
82+
const HEIGHT: u8 = 40;
83+
const OFFSETX: u8 = 28;
84+
const OFFSETY: u8 = 0;
85+
type BufferSize = U360;
86+
87+
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
88+
Command::ComPinConfig(true, false).send(iface)
89+
}
90+
}
91+
92+
/// Size information for the common 64x48 variants
93+
#[derive(Debug, Copy, Clone)]
94+
pub struct DisplaySize64x48;
95+
impl DisplaySize for DisplaySize64x48 {
96+
const WIDTH: u8 = 64;
97+
const HEIGHT: u8 = 48;
98+
const OFFSETX: u8 = 32;
99+
const OFFSETY: u8 = 0;
100+
type BufferSize = U384;
101+
102+
fn configure(&self, iface: &mut impl WriteOnlyDataCommand) -> Result<(), DisplayError> {
103+
Command::ComPinConfig(true, false).send(iface)
30104
}
31105
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ extern crate embedded_hal as hal;
144144

145145
pub mod brightness;
146146
pub mod builder;
147-
mod command;
147+
pub mod command;
148148
pub mod displayrotation;
149-
mod displaysize;
149+
pub mod displaysize;
150150
pub mod mode;
151151
pub mod prelude;
152152
pub mod properties;

src/mode/displaymode.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ use crate::Error;
55
use hal::{blocking::delay::DelayMs, digital::v2::OutputPin};
66

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

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

1515
/// Release display interface
1616
fn release(self) -> DI {

0 commit comments

Comments
 (0)