4343//! ```
4444
4545use crate :: {
46- displayrotation:: DisplayRotation , interface:: DisplayInterface ,
46+ command :: Page , displayrotation:: DisplayRotation , interface:: DisplayInterface ,
4747 mode:: displaymode:: DisplayModeTrait , properties:: DisplayProperties , Error ,
4848} ;
4949use embedded_graphics_core:: { prelude:: Point , primitives:: Rectangle } ;
5050use hal:: { blocking:: delay:: DelayMs , digital:: v2:: OutputPin } ;
5151
52- const BUFFER_SIZE : usize = 132 * 64 / 8 ;
52+ /// What to clear.
53+ #[ derive( Debug , Copy , Clone ) ]
54+ pub enum Clear {
55+ /// Clear the display buffer only, leaving the display contents alone.
56+ Buffer ,
57+
58+ /// Clear both the buffer and display.
59+ BufferAndDisplay ,
60+ }
61+
62+ // const BUFFER_SIZE: usize = 132 * 64 / 8;
63+ const W : u32 = 132 ;
64+ const H : u32 = 64 ;
5365
5466/// Graphics mode handler
5567pub struct GraphicsMode < DI >
5668where
5769 DI : DisplayInterface ,
5870{
5971 properties : DisplayProperties < DI > ,
60- buffer : [ u8 ; BUFFER_SIZE ] ,
72+ buffer : PackedBuffer < W , H , { ( W * H / 8 ) as usize } > ,
6173}
6274
6375impl < DI > DisplayModeTrait < DI > for GraphicsMode < DI >
6880 fn new ( properties : DisplayProperties < DI > ) -> Self {
6981 GraphicsMode {
7082 properties,
71- buffer : [ 0 ; BUFFER_SIZE ] ,
83+ buffer : PackedBuffer :: new ( ) ,
7284 }
7385 }
7486
@@ -82,9 +94,21 @@ impl<DI> GraphicsMode<DI>
8294where
8395 DI : DisplayInterface ,
8496{
85- /// Clear the display buffer. You need to call `display.flush()` for any effect on the screen
86- pub fn clear ( & mut self ) {
87- self . buffer = [ 0 ; BUFFER_SIZE ] ;
97+ /// Clear the display buffer.
98+ pub fn clear ( & mut self , clear : Clear ) -> Result < ( ) , DI :: Error > {
99+ self . buffer = PackedBuffer :: new ( ) ;
100+
101+ if matches ! ( clear, Clear :: BufferAndDisplay ) {
102+ let display_size = self . properties . get_size ( ) ;
103+ let column_offset = display_size. column_offset ( ) ;
104+
105+ for i in 0 ..8 {
106+ self . properties
107+ . draw_page ( Page :: from ( i * 8 ) , column_offset, & [ 0x00 ; 128 ] ) ?;
108+ }
109+ }
110+
111+ Ok ( ( ) )
88112 }
89113
90114 /// Reset display
@@ -104,72 +128,46 @@ where
104128 rst. set_high ( ) . map_err ( Error :: Pin )
105129 }
106130
107- /// Write out data to display
131+ /// Write out data to display.
108132 pub fn flush ( & mut self ) -> Result < ( ) , DI :: Error > {
109133 let display_size = self . properties . get_size ( ) ;
110134
111- // Ensure the display buffer is at the origin of the display before we send the full frame
112- // to prevent accidental offsets
113- let ( display_width, display_height) = display_size. dimensions ( ) ;
135+ let active = self . buffer . active_area ( ) . intersection ( & self . bounding_box ( ) ) ;
136+ let start_page = ( active. top_left . y / 8 ) as u8 ;
137+ let start_column = active. top_left . x as u8 ;
138+
114139 let column_offset = display_size. column_offset ( ) ;
115- self . properties . set_draw_area (
116- ( column_offset, 0 ) ,
117- ( display_width + column_offset, display_height) ,
118- ) ?;
119140
120- let length = ( display_width as usize ) * ( display_height as usize ) / 8 ;
141+ for ( i, block) in self . buffer . active_blocks ( ) . enumerate ( ) {
142+ let page = Page :: from ( ( start_page + i as u8 ) * 8 ) ;
143+
144+ self . properties
145+ . draw_page ( page, column_offset + start_column, block) ?;
146+ }
121147
122- self . properties . draw ( & self . buffer [ ..length ] )
148+ Ok ( ( ) )
123149 }
124150
125151 /// Turn a pixel on or off. A non-zero `value` is treated as on, `0` as off. If the X and Y
126152 /// coordinates are out of the bounds of the display, this method call is a noop.
127153 pub fn set_pixel ( & mut self , x : u32 , y : u32 , value : u8 ) {
128- let ( display_width, _) = self . properties . get_size ( ) . dimensions ( ) ;
129154 let display_rotation = self . properties . get_rotation ( ) ;
130155
131- let idx = match display_rotation {
132- DisplayRotation :: Rotate0 | DisplayRotation :: Rotate180 => {
133- if x >= display_width as u32 {
134- return ;
135- }
136- ( ( y as usize ) / 8 * display_width as usize ) + ( x as usize )
137- }
138-
156+ let point = match display_rotation {
157+ DisplayRotation :: Rotate0 | DisplayRotation :: Rotate180 => Point :: new ( x as i32 , y as i32 ) ,
139158 DisplayRotation :: Rotate90 | DisplayRotation :: Rotate270 => {
140- if y >= display_width as u32 {
141- return ;
142- }
143- ( ( x as usize ) / 8 * display_width as usize ) + ( y as usize )
159+ Point :: new ( y as i32 , x as i32 )
144160 }
145161 } ;
146162
147- if idx >= self . buffer . len ( ) {
148- return ;
149- }
150-
151- let ( byte, bit) = match display_rotation {
152- DisplayRotation :: Rotate0 | DisplayRotation :: Rotate180 => {
153- let byte =
154- & mut self . buffer [ ( ( y as usize ) / 8 * display_width as usize ) + ( x as usize ) ] ;
155- let bit = 1 << ( y % 8 ) ;
156-
157- ( byte, bit)
158- }
159- DisplayRotation :: Rotate90 | DisplayRotation :: Rotate270 => {
160- let byte =
161- & mut self . buffer [ ( ( x as usize ) / 8 * display_width as usize ) + ( y as usize ) ] ;
162- let bit = 1 << ( x % 8 ) ;
163-
164- ( byte, bit)
165- }
166- } ;
167-
168- if value == 0 {
169- * byte &= !bit;
170- } else {
171- * byte |= bit;
172- }
163+ self . buffer . set_pixel (
164+ point,
165+ if value == 0 {
166+ BinaryColor :: Off
167+ } else {
168+ BinaryColor :: On
169+ } ,
170+ )
173171 }
174172
175173 /// Display is set up in column mode, i.e. a byte walks down a column of 8 pixels from
@@ -202,6 +200,7 @@ use embedded_graphics_core::{
202200 pixelcolor:: BinaryColor ,
203201 Pixel ,
204202} ;
203+ use packed_display_buffer:: PackedBuffer ;
205204
206205#[ cfg( feature = "graphics" ) ]
207206impl < DI > DrawTarget for GraphicsMode < DI >
@@ -228,47 +227,14 @@ where
228227 }
229228
230229 fn fill_solid ( & mut self , area : & Rectangle , color : Self :: Color ) -> Result < ( ) , Self :: Error > {
231- let Rectangle {
232- top_left : Point { x, y } ,
233- size : Size { width, height } ,
234- } = area. intersection ( & self . bounding_box ( ) ) ;
235- // swap coordinates if rotated
236- let ( x, y, width, height) = match self . properties . get_rotation ( ) {
237- DisplayRotation :: Rotate0 | DisplayRotation :: Rotate180 => ( x, y, width, height) ,
238- DisplayRotation :: Rotate90 | DisplayRotation :: Rotate270 => ( y, x, height, width) ,
239- } ;
240-
241- let color = if color. is_on ( ) { 0xff } else { 0x00 } ;
242-
243- let display_width = self . properties . get_size ( ) . dimensions ( ) . 0 as u32 ;
244-
245- // Display is at most 128 pixels tall when rotated by 90º or 270º so we'll use a u128 here
246- let fill = 2u128 . pow ( height) - 1 ;
247- let moved = fill << y;
248-
249- let start_block = ( y / 8 ) as usize ;
250-
251- // Represents a bit mask of a single column of the entire display height
252- let whole_column = moved. to_le_bytes ( ) ;
253-
254- let end_block = start_block + ( height as usize / 8 + 1 ) ;
255-
256- // Ensure we don't wrap off the bottom of the screen
257- let end_block = end_block. min ( 7 ) ;
258-
259- for current_x in x..( x + width as i32 ) {
260- for block in start_block..=end_block {
261- let buffer_offset = current_x as usize + display_width as usize * block;
262-
263- let current = self . buffer [ buffer_offset] ;
264-
265- let mask = whole_column[ block] ;
266-
267- self . buffer [ buffer_offset] = ( current & !mask) | ( color & mask) ;
268- }
269- }
230+ self . buffer . fill_solid ( area, color)
231+ }
270232
271- Ok ( ( ) )
233+ fn fill_contiguous < I > ( & mut self , area : & Rectangle , colors : I ) -> Result < ( ) , Self :: Error >
234+ where
235+ I : IntoIterator < Item = Self :: Color > ,
236+ {
237+ self . buffer . fill_contiguous ( area, colors)
272238 }
273239}
274240
0 commit comments