Better handling for screen size not divisible by 8
Screen with width not divisible by 8 require special care when allocating the buffer and when handling rotation. Define a function for getting the needed buffer size (round up to next byte). Change how rotation is done by changing coordinates instead of direct pixel access.embedded-hal-1.0
parent
22f16eaa05
commit
82b8c98538
|
|
@ -1,5 +1,6 @@
|
||||||
//! Graphics Support for EPDs
|
//! Graphics Support for EPDs
|
||||||
|
|
||||||
|
use crate::buffer_len;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use embedded_graphics::{pixelcolor::BinaryColor, prelude::*};
|
use embedded_graphics::{pixelcolor::BinaryColor, prelude::*};
|
||||||
|
|
||||||
|
|
@ -88,6 +89,7 @@ pub trait Display: DrawTarget<BinaryColor> {
|
||||||
///
|
///
|
||||||
/// The buffer can be created as following:
|
/// The buffer can be created as following:
|
||||||
/// buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]
|
/// buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]
|
||||||
|
/// If WIDTH is not a multiple of 8, don't forget to round it up (ie. (WIDTH + 7) / 8)
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
|
|
@ -120,10 +122,10 @@ pub struct VarDisplay<'a> {
|
||||||
impl<'a> VarDisplay<'a> {
|
impl<'a> VarDisplay<'a> {
|
||||||
/// Create a new variable sized display.
|
/// Create a new variable sized display.
|
||||||
///
|
///
|
||||||
/// Buffersize must be at least width / 8 * height bytes.
|
/// Buffersize must be at least (width + 7) / 8 * height bytes.
|
||||||
pub fn new(width: u32, height: u32, buffer: &'a mut [u8]) -> VarDisplay<'a> {
|
pub fn new(width: u32, height: u32, buffer: &'a mut [u8]) -> VarDisplay<'a> {
|
||||||
let len = buffer.len() as u32;
|
let len = buffer.len() as u32;
|
||||||
assert!(width / 8 * height >= len);
|
assert!(buffer_len(width as usize, height as usize) >= len as usize);
|
||||||
VarDisplay {
|
VarDisplay {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
@ -187,29 +189,36 @@ fn outside_display(p: Point, width: u32, height: u32, rotation: DisplayRotation)
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
//returns index position in the u8-slice and the bit-position inside that u8
|
//returns index position in the u8-slice and the bit-position inside that u8
|
||||||
fn find_position(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u8) {
|
fn find_position(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u8) {
|
||||||
|
let nx;
|
||||||
|
let ny;
|
||||||
match rotation {
|
match rotation {
|
||||||
DisplayRotation::Rotate0 => (
|
DisplayRotation::Rotate0 => {
|
||||||
x / 8 + (width / 8) * y,
|
nx = x;
|
||||||
0x80 >> (x % 8),
|
ny = y;
|
||||||
),
|
},
|
||||||
DisplayRotation::Rotate90 => (
|
DisplayRotation::Rotate90 => {
|
||||||
(width - 1 - y) / 8 + (width / 8) * x,
|
nx = width - 1 - y;
|
||||||
0x01 << (y % 8),
|
ny = x;
|
||||||
),
|
} ,
|
||||||
DisplayRotation::Rotate180 => (
|
DisplayRotation::Rotate180 => {
|
||||||
((width / 8) * height - 1) - (x / 8 + (width / 8) * y),
|
nx = width - 1 - x;
|
||||||
0x01 << (x % 8),
|
ny = height - 1 - y;
|
||||||
),
|
},
|
||||||
DisplayRotation::Rotate270 => (
|
DisplayRotation::Rotate270 => {
|
||||||
y / 8 + (height - 1 - x) * (width / 8),
|
nx = y;
|
||||||
0x80 >> (y % 8),
|
ny = height - 1 - x;
|
||||||
),
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
nx / 8 + ((width + 7) / 8) * ny,
|
||||||
|
0x80 >> (nx % 8),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{find_position, outside_display, Display, DisplayRotation, VarDisplay};
|
use super::{buffer_len, find_position, outside_display, Display, DisplayRotation, VarDisplay};
|
||||||
use crate::color::Black;
|
use crate::color::Black;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use embedded_graphics::{prelude::*, primitives::Line, style::PrimitiveStyle};
|
use embedded_graphics::{prelude::*, primitives::Line, style::PrimitiveStyle};
|
||||||
|
|
@ -218,7 +227,8 @@ mod tests {
|
||||||
fn buffer_clear() {
|
fn buffer_clear() {
|
||||||
use crate::epd4in2::{HEIGHT, WIDTH};
|
use crate::epd4in2::{HEIGHT, WIDTH};
|
||||||
|
|
||||||
let mut buffer = [Color::Black.get_byte_value(); WIDTH as usize / 8 * HEIGHT as usize];
|
let mut buffer =
|
||||||
|
[Color::Black.get_byte_value(); buffer_len(WIDTH as usize, HEIGHT as usize)];
|
||||||
let mut display = VarDisplay::new(WIDTH, HEIGHT, &mut buffer);
|
let mut display = VarDisplay::new(WIDTH, HEIGHT, &mut buffer);
|
||||||
|
|
||||||
for &byte in display.buffer.iter() {
|
for &byte in display.buffer.iter() {
|
||||||
|
|
|
||||||
13
src/lib.rs
13
src/lib.rs
|
|
@ -92,6 +92,19 @@ pub mod prelude {
|
||||||
pub use crate::graphics::{Display, DisplayRotation};
|
pub use crate::graphics::{Display, DisplayRotation};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the needed buffer length. Takes care of rounding up in case width
|
||||||
|
/// is not divisible by 8.
|
||||||
|
///
|
||||||
|
/// unused
|
||||||
|
/// bits width
|
||||||
|
/// <----><------------------------>
|
||||||
|
/// [XXXXX210][76543210]...[76543210] ^
|
||||||
|
/// [XXXXX210][76543210]...[76543210] | height
|
||||||
|
/// [XXXXX210][76543210]...[76543210] v
|
||||||
|
pub const fn buffer_len(width: usize, height: usize) -> usize {
|
||||||
|
(width + 7) / 8 * height
|
||||||
|
}
|
||||||
|
|
||||||
use embedded_hal::spi::{Mode, Phase, Polarity};
|
use embedded_hal::spi::{Mode, Phase, Polarity};
|
||||||
|
|
||||||
/// SPI mode -
|
/// SPI mode -
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue