Update example to use config builder

This commit is contained in:
Wesley Moore 2018-12-26 08:43:04 +11:00
parent 242a471d4f
commit b776198b87
No known key found for this signature in database
GPG key ID: BF67766C0BC2D0EE
8 changed files with 236 additions and 177 deletions

View file

@ -5,7 +5,7 @@ use linux_embedded_hal::Delay;
use linux_embedded_hal::{Pin, Spidev}; use linux_embedded_hal::{Pin, Spidev};
extern crate ssd1675; extern crate ssd1675;
use ssd1675::{Display, Dimensions, GraphicDisplay, Color, Rotation}; use ssd1675::{Builder, Color, Dimensions, Display, GraphicDisplay, Rotation};
// Graphics // Graphics
extern crate embedded_graphics; extern crate embedded_graphics;
@ -15,12 +15,12 @@ use embedded_graphics::Drawing;
// Font // Font
extern crate profont; extern crate profont;
use profont::{ProFont9Point, ProFont12Point, ProFont14Point, ProFont24Point}; use profont::{ProFont12Point, ProFont14Point, ProFont24Point, ProFont9Point};
use std::process::Command; use std::process::Command;
use std::{fs, io};
use std::time::Duration;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration;
use std::{fs, io};
// Activate SPI, GPIO in raspi-config needs to be run with sudo because of some sysfs_gpio // Activate SPI, GPIO in raspi-config needs to be run with sudo because of some sysfs_gpio
// permission problems and follow-up timing problems // permission problems and follow-up timing problems
@ -29,6 +29,27 @@ use std::thread::sleep;
const ROWS: u16 = 212; const ROWS: u16 = 212;
const COLS: u8 = 104; const COLS: u8 = 104;
#[rustfmt::skip]
const LUT: [u8; 70] = [
// Phase 0 Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6
// A B C D A B C D A B C D A B C D A B C D A B C D A B C D
0b01001000, 0b10100000, 0b00010000, 0b00010000, 0b00010011, 0b00000000, 0b00000000, // LUT0 - Black
0b01001000, 0b10100000, 0b10000000, 0b00000000, 0b00000011, 0b00000000, 0b00000000, // LUTT1 - White
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, // IGNORE
0b01001000, 0b10100101, 0b00000000, 0b10111011, 0b00000000, 0b00000000, 0b00000000, // LUT3 - Red
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, // LUT4 - VCOM
// Duration | Repeat
// A B C D |
64, 12, 32, 12, 6, // 0 Flash
16, 8, 4, 4, 6, // 1 clear
4, 8, 8, 16, 16, // 2 bring in the black
2, 2, 2, 64, 32, // 3 time for red
2, 2, 2, 2, 2, // 4 final black sharpen phase
0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0 // 6
];
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
// Configure SPI // Configure SPI
let mut spi = Spidev::open("/dev/spidev0.0").expect("SPI device"); let mut spi = Spidev::open("/dev/spidev0.0").expect("SPI device");
@ -39,8 +60,8 @@ fn main() -> Result<(), std::io::Error> {
.build(); .build();
spi.configure(&options).expect("SPI configuration"); spi.configure(&options).expect("SPI configuration");
// https://pinout.xyz/pinout/inky_phat# // https://pinout.xyz/pinout/inky_phat
// Configure Digital I/O Pin to be used as Chip Select for SPI // Configure Digital I/O Pins
let cs = Pin::new(8); // BCM8 let cs = Pin::new(8); // BCM8
cs.export().expect("cs export"); cs.export().expect("cs export");
while !cs.is_exported() {} while !cs.is_exported() {}
@ -61,20 +82,33 @@ fn main() -> Result<(), std::io::Error> {
let reset = Pin::new(27); // BCM27 let reset = Pin::new(27); // BCM27
reset.export().expect("reset export"); reset.export().expect("reset export");
while !reset.is_exported() {} while !reset.is_exported() {}
reset.set_direction(Direction::Out).expect("reset Direction"); reset
.set_direction(Direction::Out)
.expect("reset Direction");
reset.set_value(1).expect("reset Value set to 1"); reset.set_value(1).expect("reset Value set to 1");
println!("Pins configured"); println!("Pins configured");
// Initialise display controller
let mut delay = Delay {}; let mut delay = Delay {};
let controller = ssd1675::Interface::new(spi, cs, busy, dc, reset); let controller = ssd1675::Interface::new(spi, cs, busy, dc, reset);
let dimensions = Dimensions { rows: ROWS, cols: COLS };
let mut black_buffer = [0u8; ROWS as usize * COLS as usize / 8]; let mut black_buffer = [0u8; ROWS as usize * COLS as usize / 8];
let mut red_buffer = [0u8; ROWS as usize * COLS as usize / 8]; let mut red_buffer = [0u8; ROWS as usize * COLS as usize / 8];
let display = Display::new(controller, dimensions, Rotation::Rotate270); let config = Builder::new()
.dimensions(Dimensions {
rows: ROWS,
cols: COLS,
})
.rotation(Rotation::Rotate270)
.lut(&LUT)
.build()
.expect("invalid configuration");
let display = Display::new(controller, config);
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer); let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
// Main loop. Displays CPU temperature, uname, and uptime every minute with a red Raspberry Pi
// header.
loop { loop {
display.reset(&mut delay).expect("error resetting display"); display.reset(&mut delay).expect("error resetting display");
println!("Reset and initialised"); println!("Reset and initialised");
@ -147,21 +181,29 @@ fn read_cpu_temp() -> Result<f64, io::Error> {
} }
fn read_uptime() -> Option<String> { fn read_uptime() -> Option<String> {
Command::new("uptime").arg("-p").output().ok().and_then(|output| { Command::new("uptime")
if output.status.success() { .arg("-p")
String::from_utf8(output.stdout).ok() .output()
} else { .ok()
None .and_then(|output| {
} if output.status.success() {
}) String::from_utf8(output.stdout).ok()
} else {
None
}
})
} }
fn read_uname() -> Option<String> { fn read_uname() -> Option<String> {
Command::new("uname").arg("-smr").output().ok().and_then(|output| { Command::new("uname")
if output.status.success() { .arg("-smr")
String::from_utf8(output.stdout).ok() .output()
} else { .ok()
None .and_then(|output| {
} if output.status.success() {
}) String::from_utf8(output.stdout).ok()
} else {
None
}
})
} }

View file

@ -18,7 +18,7 @@ impl From<u8> for Color {
0 => Color::Black, 0 => Color::Black,
1 => Color::White, 1 => Color::White,
2 => Color::Red, 2 => Color::Red,
_ => panic!("invalid color value") _ => panic!("invalid color value"),
} }
} }
} }

View file

@ -4,7 +4,10 @@ use interface::DisplayInterface;
const MAX_GATES: u16 = 296; const MAX_GATES: u16 = 296;
const MAX_DUMMY_LINE_PERIOD: u8 = 127; const MAX_DUMMY_LINE_PERIOD: u8 = 127;
trait Contains<C> where C: Copy + PartialOrd { trait Contains<C>
where
C: Copy + PartialOrd,
{
fn contains(&self, item: C) -> bool; fn contains(&self, item: C) -> bool;
} }
@ -173,7 +176,7 @@ fn u16_as_u8(val: u16) -> [u8; 2] {
[(val & 0xFF00 >> 8) as u8, (val & 0xFF) as u8] [(val & 0xFF00 >> 8) as u8, (val & 0xFF) as u8]
} }
/// Populates data buffer (array) and returns a pair (tuple) with command and /// Populates data buffer (array) and returns a pair (tuple) with command and
/// appropriately sized slice into populated buffer. /// appropriately sized slice into populated buffer.
/// E.g. /// E.g.
/// ///
@ -217,12 +220,8 @@ impl Command {
let [upper, lower] = u16_as_u8(gate_lines); let [upper, lower] = u16_as_u8(gate_lines);
pack!(buf, 0x01, [lower, upper, scanning_seq_and_dir]) pack!(buf, 0x01, [lower, upper, scanning_seq_and_dir])
} }
GateDrivingVoltage(voltages) => { GateDrivingVoltage(voltages) => pack!(buf, 0x03, [voltages]),
pack!(buf, 0x03, [voltages]) SourceDrivingVoltage(vsh1, vsh2, vsl) => pack!(buf, 0x04, [vsh1, vsh2, vsl]),
}
SourceDrivingVoltage(vsh1, vsh2, vsl) => {
pack!(buf, 0x04, [vsh1, vsh2, vsl])
}
BoosterEnable(phase1, phase2, phase3, duration) => { BoosterEnable(phase1, phase2, phase3, duration) => {
pack!(buf, 0x0C, [phase1, phase2, phase3, duration]) pack!(buf, 0x0C, [phase1, phase2, phase3, duration])
} }
@ -254,9 +253,7 @@ impl Command {
pack!(buf, 0x11, [axis | mode]) pack!(buf, 0x11, [axis | mode])
} }
SoftReset => { SoftReset => pack!(buf, 0x12, []),
pack!(buf, 0x12, [])
}
// TemperatatSensorSelection(TemperatureSensor) => { // TemperatatSensorSelection(TemperatureSensor) => {
// } // }
// WriteTemperatureSensor(u16) => { // WriteTemperatureSensor(u16) => {
@ -265,34 +262,22 @@ impl Command {
// } // }
// WriteExternalTemperatureSensor(u8, u8, u8) => { // WriteExternalTemperatureSensor(u8, u8, u8) => {
// } // }
UpdateDisplay => { UpdateDisplay => pack!(buf, 0x20, []),
pack!(buf, 0x20, [])
}
// UpdateDisplayOption1(RamOption, RamOption) => { // UpdateDisplayOption1(RamOption, RamOption) => {
// } // }
UpdateDisplayOption2(value) => { UpdateDisplayOption2(value) => pack!(buf, 0x22, [value]),
pack!(buf, 0x22, [value])
}
// EnterVCOMSensing => { // EnterVCOMSensing => {
// } // }
// VCOMSenseDuration(u8) => { // VCOMSenseDuration(u8) => {
// } // }
WriteVCOM(value) => { WriteVCOM(value) => pack!(buf, 0x2C, [value]),
pack!(buf, 0x2C, [value])
}
DummyLinePeriod(period) => { DummyLinePeriod(period) => {
debug_assert!(Contains::contains(&(0..=MAX_DUMMY_LINE_PERIOD), period)); debug_assert!(Contains::contains(&(0..=MAX_DUMMY_LINE_PERIOD), period));
pack!(buf, 0x3A, [period]) pack!(buf, 0x3A, [period])
} }
GateLineWidth(tgate) => { GateLineWidth(tgate) => pack!(buf, 0x3B, [tgate]),
pack!(buf, 0x3B, [tgate]) BorderWaveform(border_waveform) => pack!(buf, 0x3C, [border_waveform]),
} StartEndXPosition(start, end) => pack!(buf, 0x44, [start, end]),
BorderWaveform(border_waveform) => {
pack!(buf, 0x3C, [border_waveform])
}
StartEndXPosition(start, end) => {
pack!(buf, 0x44, [start, end])
}
StartEndYPosition(start, end) => { StartEndYPosition(start, end) => {
let [start_upper, start_lower] = u16_as_u8(start); let [start_upper, start_lower] = u16_as_u8(start);
let [end_upper, end_lower] = u16_as_u8(end); let [end_upper, end_lower] = u16_as_u8(end);
@ -302,19 +287,11 @@ impl Command {
// } // }
// AutoWriteBlackPattern(u8) => { // AutoWriteBlackPattern(u8) => {
// } // }
XAddress(address) => { XAddress(address) => pack!(buf, 0x4E, [address]),
pack!(buf, 0x4E, [address]) YAddress(address) => pack!(buf, 0x4F, [address]),
} AnalogBlockControl(value) => pack!(buf, 0x74, [value]),
YAddress(address) => { DigitalBlockControl(value) => pack!(buf, 0x7E, [value]),
pack!(buf, 0x4F, [address]) _ => unimplemented!(),
}
AnalogBlockControl(value) => {
pack!(buf, 0x74, [value])
}
DigitalBlockControl(value) => {
pack!(buf, 0x7E, [value])
}
_ => unimplemented!()
}; };
interface.send_command(command)?; interface.send_command(command)?;
@ -331,15 +308,9 @@ impl<'buf> BufCommand<'buf> {
use self::BufCommand::*; use self::BufCommand::*;
let (command, data) = match self { let (command, data) = match self {
WriteBlackData(buffer) => { WriteBlackData(buffer) => (0x24, buffer),
(0x24, buffer) WriteRedData(buffer) => (0x26, buffer),
} WriteLUT(buffer) => (0x32, buffer),
WriteRedData(buffer) => {
(0x26, buffer)
}
WriteLUT(buffer) => {
(0x32, buffer)
}
}; };
interface.send_command(command)?; interface.send_command(command)?;
@ -351,13 +322,19 @@ impl<'buf> BufCommand<'buf> {
} }
} }
impl<C> Contains<C> for core::ops::Range<C> where C: Copy + PartialOrd { impl<C> Contains<C> for core::ops::Range<C>
where
C: Copy + PartialOrd,
{
fn contains(&self, item: C) -> bool { fn contains(&self, item: C) -> bool {
item >= self.start && item < self.end item >= self.start && item < self.end
} }
} }
impl<C> Contains<C> for core::ops::RangeInclusive<C> where C: Copy + PartialOrd { impl<C> Contains<C> for core::ops::RangeInclusive<C>
where
C: Copy + PartialOrd,
{
fn contains(&self, item: C) -> bool { fn contains(&self, item: C) -> bool {
item >= *self.start() && item <= *self.end() item >= *self.start() && item <= *self.end()
} }

View file

@ -8,9 +8,10 @@ pub struct Builder<'a> {
write_lut: Option<BufCommand<'a>>, write_lut: Option<BufCommand<'a>>,
data_entry_mode: Command, data_entry_mode: Command,
dimensions: Option<Dimensions>, dimensions: Option<Dimensions>,
rotation: Rotation rotation: Rotation,
} }
#[derive(Debug)]
pub struct BuilderError {} pub struct BuilderError {}
pub struct Config<'a> { pub struct Config<'a> {
@ -20,7 +21,7 @@ pub struct Config<'a> {
pub(crate) write_lut: Option<BufCommand<'a>>, pub(crate) write_lut: Option<BufCommand<'a>>,
pub(crate) data_entry_mode: Command, pub(crate) data_entry_mode: Command,
pub(crate) dimensions: Dimensions, pub(crate) dimensions: Dimensions,
pub(crate) rotation: Rotation pub(crate) rotation: Rotation,
} }
impl<'a> Default for Builder<'a> { impl<'a> Default for Builder<'a> {
@ -30,7 +31,10 @@ impl<'a> Default for Builder<'a> {
gate_line_width: Command::GateLineWidth(0x04), gate_line_width: Command::GateLineWidth(0x04),
write_vcom: Command::WriteVCOM(0x3C), write_vcom: Command::WriteVCOM(0x3C),
write_lut: None, write_lut: None,
data_entry_mode: Command::DataEntryMode(DataEntryMode::IncrementYIncrementX, IncrementAxis::Horizontal), data_entry_mode: Command::DataEntryMode(
DataEntryMode::IncrementYIncrementX,
IncrementAxis::Horizontal,
),
dimensions: None, dimensions: None,
rotation: Rotation::default(), rotation: Rotation::default(),
} }
@ -70,7 +74,11 @@ impl<'a> Builder<'a> {
} }
} }
pub fn data_entry_mode(self, data_entry_mode: DataEntryMode, increment_axis: IncrementAxis) -> Self { pub fn data_entry_mode(
self,
data_entry_mode: DataEntryMode,
increment_axis: IncrementAxis,
) -> Self {
Self { Self {
data_entry_mode: Command::DataEntryMode(data_entry_mode, increment_axis), data_entry_mode: Command::DataEntryMode(data_entry_mode, increment_axis),
..self ..self
@ -85,10 +93,7 @@ impl<'a> Builder<'a> {
} }
pub fn rotation(self, rotation: Rotation) -> Self { pub fn rotation(self, rotation: Rotation) -> Self {
Self { Self { rotation, ..self }
rotation,
..self
}
} }
pub fn build(self) -> Result<Config<'a>, BuilderError> { pub fn build(self) -> Result<Config<'a>, BuilderError> {

View file

@ -1,7 +1,7 @@
use hal; use hal;
use config::Config;
use command::{BufCommand, Command, DataEntryMode, DeepSleepMode, IncrementAxis}; use command::{BufCommand, Command, DataEntryMode, DeepSleepMode, IncrementAxis};
use config::Config;
use interface::DisplayInterface; use interface::DisplayInterface;
// Max display resolution is 160x296 // Max display resolution is 160x296
@ -31,19 +31,28 @@ impl Default for Rotation {
} }
} }
pub struct Display<'a, I> where I: DisplayInterface { pub struct Display<'a, I>
where
I: DisplayInterface,
{
interface: I, interface: I,
config: Config<'a>, config: Config<'a>,
} }
impl<'a, I> Display<'a, I> where I: DisplayInterface { impl<'a, I> Display<'a, I>
where
I: DisplayInterface,
{
pub fn new(interface: I, config: Config<'a>) -> Self { pub fn new(interface: I, config: Config<'a>) -> Self {
// TODO: Assert dimensions are evenly divisible by 8 // TODO: Assert dimensions are evenly divisible by 8
Self { interface, config } Self { interface, config }
} }
/// Perform a hardware reset followed by software reset /// Perform a hardware reset followed by software reset
pub fn reset<D: hal::blocking::delay::DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), I::Error> { pub fn reset<D: hal::blocking::delay::DelayMs<u8>>(
&mut self,
delay: &mut D,
) -> Result<(), I::Error> {
self.interface.reset(delay); self.interface.reset(delay);
Command::SoftReset.execute(&mut self.interface)?; Command::SoftReset.execute(&mut self.interface)?;
self.interface.busy_wait(); self.interface.busy_wait();
@ -57,7 +66,8 @@ impl<'a, I> Display<'a, I> where I: DisplayInterface {
Command::AnalogBlockControl(ANALOG_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?; Command::AnalogBlockControl(ANALOG_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?;
Command::DigitalBlockControl(DIGITAL_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?; Command::DigitalBlockControl(DIGITAL_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?;
Command::DriverOutputControl(self.config.dimensions.rows, 0x00).execute(&mut self.interface)?; Command::DriverOutputControl(self.config.dimensions.rows, 0x00)
.execute(&mut self.interface)?;
self.config.dummy_line_period.execute(&mut self.interface)?; self.config.dummy_line_period.execute(&mut self.interface)?;
self.config.gate_line_width.execute(&mut self.interface)?; self.config.gate_line_width.execute(&mut self.interface)?;
@ -83,7 +93,12 @@ impl<'a, I> Display<'a, I> where I: DisplayInterface {
Ok(()) Ok(())
} }
pub fn update<D: hal::blocking::delay::DelayMs<u8>>(&mut self, black: &[u8], red: &[u8], delay: &mut D) -> Result<(), I::Error> { pub fn update<D: hal::blocking::delay::DelayMs<u8>>(
&mut self,
black: &[u8],
red: &[u8],
delay: &mut D,
) -> Result<(), I::Error> {
// Write the B/W RAM // Write the B/W RAM
let buf_limit = ((self.rows() * self.cols() as u16) as f32 / 8.).ceil() as usize; let buf_limit = ((self.rows() * self.cols() as u16) as f32 / 8.).ceil() as usize;
Command::XAddress(0).execute(&mut self.interface)?; Command::XAddress(0).execute(&mut self.interface)?;
@ -124,23 +139,3 @@ impl<'a, I> Display<'a, I> where I: DisplayInterface {
self.config.rotation self.config.rotation
} }
} }
const LUT_RED: [u8; 70] = [
// Phase 0 Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6
// A B C D A B C D A B C D A B C D A B C D A B C D A B C D
0b01001000, 0b10100000, 0b00010000, 0b00010000, 0b00010011, 0b00000000, 0b00000000, // LUT0 - Black
0b01001000, 0b10100000, 0b10000000, 0b00000000, 0b00000011, 0b00000000, 0b00000000, // LUTT1 - White
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, // IGNORE
0b01001000, 0b10100101, 0b00000000, 0b10111011, 0b00000000, 0b00000000, 0b00000000, // LUT3 - Red
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, // LUT4 - VCOM
// Duration | Repeat
// A B C D |
64, 12, 32, 12, 6, // 0 Flash
16, 8, 4, 4, 6, // 1 clear
4, 8, 8, 16, 16, // 2 bring in the black
2, 2, 2, 64, 32, // 3 time for red
2, 2, 2, 2, 2, // 4 final black sharpen phase
0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0 // 6
];

View file

@ -1,22 +1,40 @@
use hal;
use color::Color; use color::Color;
use display::{Display, Rotation};
use interface::DisplayInterface;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use display::{Display, Rotation};
use hal;
use interface::DisplayInterface;
pub struct GraphicDisplay<'a, I> where I: DisplayInterface { pub struct GraphicDisplay<'a, I>
where
I: DisplayInterface,
{
display: Display<'a, I>, display: Display<'a, I>,
black_buffer: &'a mut [u8], black_buffer: &'a mut [u8],
red_buffer: &'a mut [u8], red_buffer: &'a mut [u8],
} }
impl<'a, I> GraphicDisplay<'a, I> where I: DisplayInterface { impl<'a, I> GraphicDisplay<'a, I>
pub fn new(display: Display<'a, I>, black_buffer: &'a mut [u8], red_buffer: &'a mut [u8]) -> Self { where
GraphicDisplay { display, black_buffer, red_buffer } I: DisplayInterface,
{
pub fn new(
display: Display<'a, I>,
black_buffer: &'a mut [u8],
red_buffer: &'a mut [u8],
) -> Self {
GraphicDisplay {
display,
black_buffer,
red_buffer,
}
} }
pub fn update<D: hal::blocking::delay::DelayMs<u8>>(&mut self, delay: &mut D) -> Result<(), I::Error> { pub fn update<D: hal::blocking::delay::DelayMs<u8>>(
self.display.update(self.black_buffer, self.red_buffer, delay) &mut self,
delay: &mut D,
) -> Result<(), I::Error> {
self.display
.update(self.black_buffer, self.red_buffer, delay)
} }
pub fn clear(&mut self, color: Color) { pub fn clear(&mut self, color: Color) {
@ -37,7 +55,13 @@ impl<'a, I> GraphicDisplay<'a, I> where I: DisplayInterface {
} }
fn set_pixel(&mut self, x: u32, y: u32, color: Color) { fn set_pixel(&mut self, x: u32, y: u32, color: Color) {
let (index, bit) = rotation(x, y, self.cols() as u32, self.rows() as u32, self.rotation()); let (index, bit) = rotation(
x,
y,
self.cols() as u32,
self.rows() as u32,
self.rotation(),
);
let index = index as usize; let index = index as usize;
match color { match color {
@ -57,7 +81,10 @@ impl<'a, I> GraphicDisplay<'a, I> where I: DisplayInterface {
} }
} }
impl<'a, I> Deref for GraphicDisplay<'a, I> where I: DisplayInterface { impl<'a, I> Deref for GraphicDisplay<'a, I>
where
I: DisplayInterface,
{
type Target = Display<'a, I>; type Target = Display<'a, I>;
fn deref(&self) -> &Display<'a, I> { fn deref(&self) -> &Display<'a, I> {
@ -65,7 +92,10 @@ impl<'a, I> Deref for GraphicDisplay<'a, I> where I: DisplayInterface {
} }
} }
impl<'a, I> DerefMut for GraphicDisplay<'a, I> where I: DisplayInterface { impl<'a, I> DerefMut for GraphicDisplay<'a, I>
where
I: DisplayInterface,
{
fn deref_mut(&mut self) -> &mut Display<'a, I> { fn deref_mut(&mut self) -> &mut Display<'a, I> {
&mut self.display &mut self.display
} }
@ -73,22 +103,13 @@ impl<'a, I> DerefMut for GraphicDisplay<'a, I> where I: DisplayInterface {
fn rotation(x: u32, y: u32, width: u32, height: u32, rotation: Rotation) -> (u32, u8) { fn rotation(x: u32, y: u32, width: u32, height: u32, rotation: Rotation) -> (u32, u8) {
match rotation { match rotation {
Rotation::Rotate0 => ( Rotation::Rotate0 => (x / 8 + (width / 8) * y, 0x80 >> (x % 8)),
x / 8 + (width / 8) * y, Rotation::Rotate90 => ((width - 1 - y) / 8 + (width / 8) * x, 0x01 << (y % 8)),
0x80 >> (x % 8),
),
Rotation::Rotate90 => (
(width - 1 - y) / 8 + (width / 8) * x,
0x01 << (y % 8),
),
Rotation::Rotate180 => ( Rotation::Rotate180 => (
((width / 8) * height - 1) - (x / 8 + (width / 8) * y), ((width / 8) * height - 1) - (x / 8 + (width / 8) * y),
0x01 << (x % 8), 0x01 << (x % 8),
), ),
Rotation::Rotate270 => ( Rotation::Rotate270 => (y / 8 + (height - 1 - x) * (width / 8), 0x80 >> (y % 8)),
y / 8 + (height - 1 - x) * (width / 8),
0x80 >> (y % 8),
),
} }
} }
@ -112,7 +133,7 @@ fn outside_display(x: u32, y: u32, width: u32, height: u32, rotation: Rotation)
#[cfg(feature = "graphics")] #[cfg(feature = "graphics")]
extern crate embedded_graphics; extern crate embedded_graphics;
#[cfg(feature = "graphics")] #[cfg(feature = "graphics")]
use self::embedded_graphics::{drawable::Pixel, Drawing, prelude::UnsignedCoord}; use self::embedded_graphics::{drawable::Pixel, prelude::UnsignedCoord, Drawing};
#[cfg(feature = "graphics")] #[cfg(feature = "graphics")]
impl<'a, I> Drawing<Color> for GraphicDisplay<'a, I> impl<'a, I> Drawing<Color> for GraphicDisplay<'a, I>
@ -124,7 +145,13 @@ where
T: Iterator<Item = Pixel<Color>>, T: Iterator<Item = Pixel<Color>>,
{ {
for Pixel(UnsignedCoord(x, y), colour) in item_pixels { for Pixel(UnsignedCoord(x, y), colour) in item_pixels {
if outside_display(x, y, self.cols() as u32, self.rows() as u32, self.rotation()) { if outside_display(
x,
y,
self.cols() as u32,
self.rows() as u32,
self.rotation(),
) {
continue; continue;
} }
@ -135,13 +162,13 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use ::{Display, DisplayInterface, Dimensions, GraphicDisplay, Color, Rotation};
use self::embedded_graphics::coord::Coord; use self::embedded_graphics::coord::Coord;
use self::embedded_graphics::fonts::{Font12x16, Font6x8}; use self::embedded_graphics::fonts::{Font12x16, Font6x8};
use self::embedded_graphics::prelude::*; use self::embedded_graphics::prelude::*;
use self::embedded_graphics::primitives::{Circle, Line, Rect}; use self::embedded_graphics::primitives::{Circle, Line, Rect};
use self::embedded_graphics::Drawing; use self::embedded_graphics::Drawing;
use super::*;
use {Color, Dimensions, Display, DisplayInterface, GraphicDisplay, Rotation};
const ROWS: u16 = 3; const ROWS: u16 = 3;
const COLS: u8 = 8; const COLS: u8 = 8;
@ -191,15 +218,18 @@ mod tests {
#[test] #[test]
fn clear_white() { fn clear_white() {
let interface = MockInterface::new(); let interface = MockInterface::new();
let dimensions = Dimensions { rows: ROWS, cols: COLS }; let dimensions = Dimensions {
rows: ROWS,
cols: COLS,
};
let mut black_buffer = [0u8; BUFFER_SIZE]; let mut black_buffer = [0u8; BUFFER_SIZE];
let mut red_buffer = [0u8; BUFFER_SIZE]; let mut red_buffer = [0u8; BUFFER_SIZE];
{ {
let display = Display::new(interface, dimensions, Rotation::Rotate270); let display = Display::new(interface, dimensions, Rotation::Rotate270);
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer); let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
display.clear(Color::White); display.clear(Color::White);
} }
assert_eq!(black_buffer, [0xFF, 0xFF, 0xFF]); assert_eq!(black_buffer, [0xFF, 0xFF, 0xFF]);
@ -209,15 +239,18 @@ mod tests {
#[test] #[test]
fn clear_black() { fn clear_black() {
let interface = MockInterface::new(); let interface = MockInterface::new();
let dimensions = Dimensions { rows: ROWS, cols: COLS }; let dimensions = Dimensions {
rows: ROWS,
cols: COLS,
};
let mut black_buffer = [0u8; BUFFER_SIZE]; let mut black_buffer = [0u8; BUFFER_SIZE];
let mut red_buffer = [0u8; BUFFER_SIZE]; let mut red_buffer = [0u8; BUFFER_SIZE];
{ {
let display = Display::new(interface, dimensions, Rotation::Rotate270); let display = Display::new(interface, dimensions, Rotation::Rotate270);
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer); let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
display.clear(Color::Black); display.clear(Color::Black);
} }
assert_eq!(black_buffer, [0x00, 0x00, 0x00]); assert_eq!(black_buffer, [0x00, 0x00, 0x00]);
@ -227,15 +260,18 @@ mod tests {
#[test] #[test]
fn clear_red() { fn clear_red() {
let interface = MockInterface::new(); let interface = MockInterface::new();
let dimensions = Dimensions { rows: ROWS, cols: COLS }; let dimensions = Dimensions {
rows: ROWS,
cols: COLS,
};
let mut black_buffer = [0u8; BUFFER_SIZE]; let mut black_buffer = [0u8; BUFFER_SIZE];
let mut red_buffer = [0u8; BUFFER_SIZE]; let mut red_buffer = [0u8; BUFFER_SIZE];
{ {
let display = Display::new(interface, dimensions, Rotation::Rotate270); let display = Display::new(interface, dimensions, Rotation::Rotate270);
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer); let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
display.clear(Color::Red); display.clear(Color::Red);
} }
assert_eq!(black_buffer, [0xFF, 0xFF, 0xFF]); assert_eq!(black_buffer, [0xFF, 0xFF, 0xFF]);
@ -245,45 +281,50 @@ mod tests {
#[test] #[test]
fn draw_rect_white() { fn draw_rect_white() {
let interface = MockInterface::new(); let interface = MockInterface::new();
let dimensions = Dimensions { rows: ROWS, cols: COLS }; let dimensions = Dimensions {
rows: ROWS,
cols: COLS,
};
let mut black_buffer = [0u8; BUFFER_SIZE]; let mut black_buffer = [0u8; BUFFER_SIZE];
let mut red_buffer = [0u8; BUFFER_SIZE]; let mut red_buffer = [0u8; BUFFER_SIZE];
{ {
let display = Display::new(interface, dimensions, Rotation::Rotate0); let display = Display::new(interface, dimensions, Rotation::Rotate0);
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer); let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
display.draw(Rect::new(Coord::new(0,0), Coord::new(2, 2)).with_stroke(Some(Color::White)).into_iter()); display.draw(
Rect::new(Coord::new(0, 0), Coord::new(2, 2))
.with_stroke(Some(Color::White))
.into_iter(),
);
} }
assert_eq!(black_buffer, [ assert_eq!(black_buffer, [0b11100000, 0b10100000, 0b11100000]);
0b11100000,
0b10100000,
0b11100000]);
assert_eq!(red_buffer, [0b00000000, 0b00000000, 0b00000000]); assert_eq!(red_buffer, [0b00000000, 0b00000000, 0b00000000]);
} }
#[test] #[test]
fn draw_rect_red() { fn draw_rect_red() {
let interface = MockInterface::new(); let interface = MockInterface::new();
let dimensions = Dimensions { rows: ROWS, cols: COLS }; let dimensions = Dimensions {
rows: ROWS,
cols: COLS,
};
let mut black_buffer = [0u8; BUFFER_SIZE]; let mut black_buffer = [0u8; BUFFER_SIZE];
let mut red_buffer = [0u8; BUFFER_SIZE]; let mut red_buffer = [0u8; BUFFER_SIZE];
{ {
let display = Display::new(interface, dimensions, Rotation::Rotate0); let display = Display::new(interface, dimensions, Rotation::Rotate0);
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer); let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
display.draw(Rect::new(Coord::new(1,0), Coord::new(3, 2)).with_stroke(Some(Color::Red)).into_iter()); display.draw(
Rect::new(Coord::new(1, 0), Coord::new(3, 2))
.with_stroke(Some(Color::Red))
.into_iter(),
);
} }
assert_eq!(black_buffer, [ assert_eq!(black_buffer, [0b01110000, 0b01010000, 0b01110000]);
0b01110000, assert_eq!(red_buffer, [0b01110000, 0b01010000, 0b01110000]);
0b01010000,
0b01110000]);
assert_eq!(red_buffer, [
0b01110000,
0b01010000,
0b01110000]);
} }
} }

View file

@ -64,10 +64,9 @@ where
Ok(()) Ok(())
} }
} }
impl<SPI, CS, BUSY, DC, RESET> DisplayInterface for Interface<SPI, CS, BUSY, DC, RESET> impl<SPI, CS, BUSY, DC, RESET> DisplayInterface for Interface<SPI, CS, BUSY, DC, RESET>
where where
SPI: hal::blocking::spi::Write<u8>, SPI: hal::blocking::spi::Write<u8>,
CS: hal::digital::OutputPin, CS: hal::digital::OutputPin,

View file

@ -13,9 +13,9 @@ mod display;
mod graphics; mod graphics;
mod interface; mod interface;
pub use interface::DisplayInterface;
pub use interface::Interface;
pub use display::{Display, Dimensions, Rotation};
pub use graphics::GraphicDisplay;
pub use color::Color; pub use color::Color;
pub use config::Builder; pub use config::Builder;
pub use display::{Dimensions, Display, Rotation};
pub use graphics::GraphicDisplay;
pub use interface::DisplayInterface;
pub use interface::Interface;