diff --git a/src/drawing/color.rs b/src/drawing/color.rs index 1ee507d..1031294 100644 --- a/src/drawing/color.rs +++ b/src/drawing/color.rs @@ -1,7 +1,7 @@ /// Only for the B/W Displays atm pub enum Color { Black, - White + White, } impl Color { @@ -9,7 +9,7 @@ impl Color { pub fn get_bit_value(&self) -> u8 { match self { Color::White => 1u8, - Color::Black => 0u8, + Color::Black => 0u8, } } @@ -21,9 +21,8 @@ impl Color { } } - /// Get the color encoding of a specific bit in a byte - /// + /// /// input is the byte where one bit is gonna be selected /// pos is counted from the left (highest value) from 0 to 7 /// remember: 1 is white, 0 is black @@ -61,7 +60,7 @@ impl Color { //TODO: does basically the same as get_color, so remove one of them? pub(crate) fn convert_color(input: u8, pos: u8, foreground_color: &Color) -> Color { - //match color: + //match color: // - white for "nothing to draw"/background drawing // - black for pixel to draw // @@ -72,4 +71,4 @@ impl Color { Color::inverse_color(foreground_color) } } -} \ No newline at end of file +} diff --git a/src/drawing/font.rs b/src/drawing/font.rs index 92d18cc..a63bf37 100644 --- a/src/drawing/font.rs +++ b/src/drawing/font.rs @@ -11,20 +11,33 @@ pub struct Font<'a> { first_char: u8, last_char: u8, bitmap: &'a [u8], - widthmap: &'a [u8] + widthmap: &'a [u8], } impl<'a> Font<'a> { /// Panics if either Bitmap or Widthmap of the Font are to small for the amount and size of chars - pub fn new(width: u8, height: u8, first_char: u8, last_char: u8, bitmap: &'a [u8], widthmap: &'a [u8]) -> Font<'a> { + pub fn new( + width: u8, + height: u8, + first_char: u8, + last_char: u8, + bitmap: &'a [u8], + widthmap: &'a [u8], + ) -> Font<'a> { //Assertion so it shouldn't be able to panic later let length_of_char = width as usize / 8 * height as usize; let amount_of_chars = last_char as usize - first_char as usize + 1; assert!(bitmap.len() >= amount_of_chars * length_of_char); assert!(widthmap.len() >= amount_of_chars); - Font {width, height, first_char, last_char, bitmap, widthmap } - + Font { + width, + height, + first_char, + last_char, + bitmap, + widthmap, + } } fn get_length_of_char(&self) -> usize { @@ -40,7 +53,7 @@ impl<'a> Font<'a> { let start_pos = self.get_char_pos(input) * self.get_length_of_char(); let end_pos = start_pos + self.get_length_of_char(); - &self.bitmap[start_pos .. end_pos] + &self.bitmap[start_pos..end_pos] } /// Can panic, when get_char_pos > widthmap.len(), should be caught in Font::new already @@ -49,7 +62,6 @@ impl<'a> Font<'a> { } } - #[cfg(test)] mod tests { use super::*; @@ -64,9 +76,10 @@ mod tests { 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, // '!' 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, // '"' 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00, 0x00, // '#' - 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00, 0x00]; // '$' + 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00, 0x00, // '$' + ]; - let widthmap = [8,8,8,8]; + let widthmap = [8, 8, 8, 8]; let font = Font::new(8, 8, '!' as u8, '$' as u8, &bitmap, &widthmap); @@ -80,9 +93,6 @@ mod tests { assert_eq!(font.get_char_width('$'), widthmap[3]); } - - - #[test] fn bitmap_8x8_test() { let and = [0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x00, 0x00]; @@ -90,7 +100,7 @@ mod tests { let first_value = [0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00]; let last_value = [0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, 0x00]; - assert_eq!(bitmap_8x8('&'), and); + assert_eq!(bitmap_8x8('&'), and); assert_eq!(bitmap_8x8('ß'), zero); assert_eq!(bitmap_8x8('°'), zero); @@ -98,13 +108,10 @@ mod tests { assert_eq!(bitmap_8x8('!'), first_value); assert_eq!(bitmap_8x8('}'), last_value); - assert_eq!(bitmap_8x8('0')[1], 0x3E); + assert_eq!(bitmap_8x8('0')[1], 0x3E); } } - - - //bad font as the order is not the one we want to use //goes from bottom left -> up -> right pub(crate) fn bitmap_8x8(input: char) -> [u8; 8] { diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs index 08763cd..672010d 100644 --- a/src/drawing/mod.rs +++ b/src/drawing/mod.rs @@ -1,11 +1,9 @@ - pub mod font; use self::font::Font; pub mod color; use self::color::Color; - #[derive(Clone, Copy)] pub enum Displayorientation { /// No rotation @@ -42,28 +40,30 @@ impl Display { /// - Neccessary Buffersize pub fn get_dimensions(&self) -> (u16, u16, u16) { match self { - Display::Eink42BlackWhite => (400, 300, 15000) + Display::Eink42BlackWhite => (400, 300, 15000), } } } - - #[allow(dead_code)] pub struct Graphics<'a> { width: u16, height: u16, rotation: Displayorientation, - buffer: &'a mut [u8] - //buffer: Box//[u8; 15000], + buffer: &'a mut [u8], //buffer: Box//[u8; 15000] } impl<'a> Graphics<'a> { /// width needs to be a multiple of 8! - pub fn new(width: u16, height: u16, buffer: &'a mut [u8]) -> Graphics<'a>{ + pub fn new(width: u16, height: u16, buffer: &'a mut [u8]) -> Graphics<'a> { let len = buffer.len(); assert!(width / 8 * height >= len as u16); - Graphics {width, height, rotation: Displayorientation::Rotate0, buffer} + Graphics { + width, + height, + rotation: Displayorientation::Rotate0, + buffer, + } } /// Clears/Fills the full buffer with `color` @@ -78,16 +78,18 @@ impl<'a> Graphics<'a> { } /// Draw a single Pixel with `color` - /// + /// /// limited to i16::max images (buffer_size) at the moment pub fn draw_pixel(&mut self, x: u16, y: u16, color: &Color) { let (idx, bit) = match self.rotation { - Displayorientation::Rotate0 | Displayorientation::Rotate180 - => ((x as usize / 8 + (self.width as usize / 8) * y as usize) , - 0x80 >> (x % 8)), - Displayorientation::Rotate90 | Displayorientation::Rotate270 - => (y as usize / 8 * self.width as usize + x as usize, - 0x80 >> (y % 8)), + Displayorientation::Rotate0 | Displayorientation::Rotate180 => ( + (x as usize / 8 + (self.width as usize / 8) * y as usize), + 0x80 >> (x % 8), + ), + Displayorientation::Rotate90 | Displayorientation::Rotate270 => ( + y as usize / 8 * self.width as usize + x as usize, + 0x80 >> (y % 8), + ), }; if idx >= self.buffer.len() { @@ -96,8 +98,8 @@ impl<'a> Graphics<'a> { match color { Color::Black => { - self.buffer[idx] &= !bit; - }, + self.buffer[idx] &= !bit; + } Color::White => { self.buffer[idx] |= bit; } @@ -105,15 +107,17 @@ impl<'a> Graphics<'a> { } /// Draw a single Pixel with `color` - /// + /// /// limited to i16::max images (buffer_size) at the moment #[allow(dead_code)] fn draw_byte(&mut self, x: u16, y: u16, filling: u8, color: &Color) { let idx = match self.rotation { - Displayorientation::Rotate0 | Displayorientation::Rotate180 - => x as usize / 8 + (self.width as usize / 8) * y as usize, - Displayorientation::Rotate90 | Displayorientation::Rotate270 - => y as usize / 8 + (self.width as usize / 8) * x as usize, + Displayorientation::Rotate0 | Displayorientation::Rotate180 => { + x as usize / 8 + (self.width as usize / 8) * y as usize + }, + Displayorientation::Rotate90 | Displayorientation::Rotate270 => { + y as usize / 8 + (self.width as usize / 8) * x as usize + }, }; if idx >= self.buffer.len() { @@ -122,7 +126,7 @@ impl<'a> Graphics<'a> { match color { Color::Black => { - self.buffer[idx] = !filling; + self.buffer[idx] = !filling; }, Color::White => { self.buffer[idx] = filling; @@ -145,7 +149,6 @@ impl<'a> Graphics<'a> { } } - //TODO: add support for font_height = 0 //TODO: add support for char offset in y direction to reduce font file size fn draw_char_helper(&mut self, x0: u16, y0: u16, input: char, font: &Font, color: &Color) { @@ -156,18 +159,17 @@ impl<'a> Graphics<'a> { let buff = font.get_char(input); let char_width = font.get_char_width(input); - let mut row_counter = 0; let mut width_counter = 0u8; for &elem in buff.iter() { for _ in 0..8 { + self.draw_pixel( + x0 + u16::from(width_counter), + y0 + row_counter, + &Color::get_color(elem, width_counter % 8, color), + ); - self.draw_pixel( - x0 + u16::from(width_counter), - y0 + row_counter, - &Color::get_color(elem, width_counter % 8, color)); - - //Widthcounter shows how far we are in x direction + //Widthcounter shows how far we are in x direction width_counter += 1; // if we have reached if width_counter >= char_width { @@ -185,39 +187,48 @@ impl<'a> Graphics<'a> { // includes special draw_char instructions as this one is ordered columnwise and not rowwise (first byte == first 8 pixel columnwise) for &elem in (&font::bitmap_8x8(input)).iter() { for i in 0..8u8 { - self.draw_pixel(x0 + counter, y0 + 7 - u16::from(i), &Color::convert_color(elem, i, color)) + self.draw_pixel( + x0 + counter, + y0 + 7 - u16::from(i), + &Color::convert_color(elem, i, color), + ) } counter += 1; } } /// Draws Strings with 8x8 Chars (1 pixel padding included) - /// + /// /// Is quite small for the 400x300 E-Ink - /// + /// /// no autobreak line yet pub fn draw_string_8x8(&mut self, x0: u16, y0: u16, input: &str, color: &Color) { for (counter, input_char) in input.chars().enumerate() { - self.draw_char_8x8(x0 + counter as u16*8, y0, input_char, color); + self.draw_char_8x8( + x0 + counter as u16 * 8, + y0, + input_char, + color, + ); } } -// void plotLine(int x0, int y0, int x1, int y1) -// { -// int dx = abs(x1-x0), sx = x0= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */ -// if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */ -// } -// } + // void plotLine(int x0, int y0, int x1, int y1) + // { + // int dx = abs(x1-x0), sx = x0= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */ + // if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */ + // } + // } //bresenham algorithm for lines - /// draw line + /// draw line pub fn draw_line(&mut self, x0: u16, y0: u16, x1: u16, y1: u16, color: &Color) { let mut x0 = x0 as i16; let x1 = x1 as i16; @@ -227,9 +238,9 @@ impl<'a> Graphics<'a> { let dx = i16::abs(x1 - x0); let sx = if x0 < x1 { 1 } else { -1 }; - let dy = - i16::abs(y1 - y0); + let dy = -i16::abs(y1 - y0); let sy = if y0 < y1 { 1 } else { -1 }; - + let mut err = dx + dy; loop { @@ -239,7 +250,7 @@ impl<'a> Graphics<'a> { break; } - let e2 = 2*err; + let e2 = 2 * err; if e2 >= dy { err += dy; @@ -253,7 +264,7 @@ impl<'a> Graphics<'a> { } } - /// Draw a horizontal line + /// Draw a horizontal line /// TODO: maybe optimize by grouping up the bytes? But is it worth the longer and more complicated function? is it even faster? pub fn draw_horizontal_line(&mut self, x: u16, y: u16, length: u16, color: &Color) { for i in 0..length { @@ -297,69 +308,63 @@ impl<'a> Graphics<'a> { } } + fn draw_circle_helper(&mut self, x0: u16, y0: u16, radius: u16, filled: bool, color: &Color) { + let mut x = radius - 1; + let mut y = 0; + let mut dx = 1; + let mut dy = 1; + let mut err: i16 = dx - 2 * radius as i16; -fn draw_circle_helper(&mut self, x0: u16, y0: u16, radius: u16, filled: bool, color: &Color) { - let mut x = radius - 1; - let mut y = 0; - let mut dx = 1; - let mut dy = 1; - let mut err: i16 = dx - 2 * radius as i16; - - while x >= y { - if filled { - self.circle_helper_filled_putpixel(x0, y0, x, y, color); - } else { - self.circle_helper_putpixel(x0, y0, x, y, color); - } + while x >= y { + if filled { + self.circle_helper_filled_putpixel(x0, y0, x, y, color); + } else { + self.circle_helper_putpixel(x0, y0, x, y, color); + } - if err <= 0 { - y += 1; - err += dy; - dy += 2; - } + if err <= 0 { + y += 1; + err += dy; + dy += 2; + } - if err > 0 { - x -= 1; - dx += 2; - err += dx - 2 * radius as i16; + if err > 0 { + x -= 1; + dx += 2; + err += dx - 2 * radius as i16; + } } } -} - -fn circle_helper_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, color: &Color) { - self.draw_horizontal_line(x0 - x, y0 + y, 2*x, color); - // self.draw_pixel(buffer, x0 + x, y0 + y, color); - // self.draw_pixel(buffer, x0 - x, y0 + y, color); - - self.draw_horizontal_line(x0 - y, y0 + x, 2*y, color); - // self.draw_pixel(buffer, x0 + y, y0 + x, color); - // self.draw_pixel(buffer, x0 - y, y0 + x, color); - - self.draw_horizontal_line(x0 - x, y0 - y, 2*x, color); - // self.draw_pixel(buffer, x0 - x, y0 - y, color); - // self.draw_pixel(buffer, x0 + x, y0 - y, color); - - self.draw_horizontal_line(x0 - y, y0 - y, 2*y, color); - // self.draw_pixel(buffer, x0 - y, y0 - x, color); - // self.draw_pixel(buffer, x0 + y, y0 - x, color); - -} + fn circle_helper_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, color: &Color) { + self.draw_horizontal_line(x0 - x, y0 + y, 2 * x, color); + // self.draw_pixel(buffer, x0 + x, y0 + y, color); + // self.draw_pixel(buffer, x0 - x, y0 + y, color); -//TODO: Test -fn circle_helper_filled_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, color: &Color) { - self.draw_pixel(x0 + x, y0 + y, color); - self.draw_pixel(x0 + y, y0 + x, color); - self.draw_pixel(x0 - y, y0 + x, color); - self.draw_pixel(x0 - x, y0 + y, color); - self.draw_pixel(x0 - x, y0 - y, color); - self.draw_pixel(x0 - y, y0 - x, color); - self.draw_pixel(x0 + y, y0 - x, color); - self.draw_pixel(x0 + x, y0 - y, color); -} + self.draw_horizontal_line(x0 - y, y0 + x, 2 * y, color); + // self.draw_pixel(buffer, x0 + y, y0 + x, color); + // self.draw_pixel(buffer, x0 - y, y0 + x, color); + self.draw_horizontal_line(x0 - x, y0 - y, 2 * x, color); + // self.draw_pixel(buffer, x0 - x, y0 - y, color); + // self.draw_pixel(buffer, x0 + x, y0 - y, color); + self.draw_horizontal_line(x0 - y, y0 - y, 2 * y, color); + // self.draw_pixel(buffer, x0 - y, y0 - x, color); + // self.draw_pixel(buffer, x0 + y, y0 - x, color); + } + //TODO: Test + fn circle_helper_filled_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, color: &Color) { + self.draw_pixel(x0 + x, y0 + y, color); + self.draw_pixel(x0 + y, y0 + x, color); + self.draw_pixel(x0 - y, y0 + x, color); + self.draw_pixel(x0 - x, y0 + y, color); + self.draw_pixel(x0 - x, y0 - y, color); + self.draw_pixel(x0 - y, y0 - x, color); + self.draw_pixel(x0 + y, y0 - x, color); + self.draw_pixel(x0 + x, y0 - y, color); + } ///TODO: test if circle looks good /// Draws a circle @@ -373,7 +378,7 @@ fn circle_helper_filled_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, c let radius = radius as i16; let x_mid = x as i16; let y_mid = y as i16; - let mut x_pos: i16 = 0 - radius; + let mut x_pos: i16 = 0 - radius; let mut y_pos = 0; let mut err: i16 = 2 - 2 * radius; @@ -387,12 +392,12 @@ fn circle_helper_filled_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, c if radius <= y_pos { y_pos += 1; - err += y_pos*2 + 1; + err += y_pos * 2 + 1; } if radius > x_pos || err > y_pos { x_pos += 1; - err += x_pos*2 + 1; + err += x_pos * 2 + 1; } if x_pos >= 0 { @@ -401,16 +406,12 @@ fn circle_helper_filled_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, c } } - ///TODO: test! pub fn draw_filled_circle(&mut self, x0: u16, y0: u16, radius: u16, color: &Color) { self.draw_circle_helper(x0, y0, radius, true, color); } - - } - /* ############ ############ ############ ############ @@ -424,8 +425,6 @@ fn circle_helper_filled_putpixel(&mut self, x0: u16, y0: u16, x: u16, y: u16, c */ - - #[cfg(test)] mod graphics { use super::*; @@ -435,15 +434,12 @@ mod graphics { let mut buffer = [Color::White.get_byte_value(); 150]; let mut graphics = Graphics::new(40, 30, &mut buffer); graphics.draw_filled_rectangle(0, 0, 40, 30, &Color::Black); - + assert_eq!(graphics.buffer[0], Color::Black.get_byte_value()); for &elem in graphics.buffer.iter() { - assert_eq!(elem, Color::Black.get_byte_value()); } - - } /// draw a 4x4 in the top left corner @@ -452,12 +448,12 @@ mod graphics { let mut buffer = [Color::White.get_byte_value(); 8]; let mut graphics = Graphics::new(8, 8, &mut buffer); graphics.draw_filled_rectangle(0, 0, 4, 4, &Color::Black); - + assert_eq!(graphics.buffer[0], 0x0f); let mut counter = 0; for &elem in graphics.buffer.iter() { - counter += 1; + counter += 1; if counter <= 4 { assert_eq!(elem, 0x0f); @@ -465,8 +461,6 @@ mod graphics { assert_eq!(elem, Color::White.get_byte_value()); } } - - } #[test] @@ -474,7 +468,7 @@ mod graphics { let mut buffer = [Color::White.get_byte_value(); 4]; let mut graphics = Graphics::new(16, 2, &mut buffer); graphics.draw_horizontal_line(1, 0, 14, &Color::Black); - + assert_eq!(graphics.buffer[0], 0x80); assert_eq!(graphics.buffer[1], 0x01); assert_eq!(graphics.buffer[2], Color::White.get_byte_value()); @@ -488,12 +482,10 @@ mod graphics { graphics.draw_vertical_line(0, 0, 8, &Color::Black); graphics.draw_vertical_line(5, 0, 8, &Color::Black); - - + assert_eq!(graphics.buffer[0], 0x7b); for &elem in graphics.buffer.iter() { - assert_eq!(elem, 0x7bu8); } } @@ -509,9 +501,9 @@ mod graphics { let mut buffer2 = [Color::White.get_byte_value(); 8]; let mut graphics2 = Graphics::new(8, 8, &mut buffer2); - graphics2.draw_line(5, 0, 5, 8, &Color::Black); + graphics2.draw_line(5, 0, 5, 8, &Color::Black); - for i in 0..graphics.buffer.len() { + for i in 0..graphics.buffer.len() { assert_eq!(graphics.buffer[i], graphics2.buffer[i]); } } @@ -525,9 +517,9 @@ mod graphics { let mut buffer2 = [Color::White.get_byte_value(); 4]; let mut graphics2 = Graphics::new(16, 2, &mut buffer2); - graphics2.draw_line(1, 0, 14, 0, &Color::Black); + graphics2.draw_line(1, 0, 14, 0, &Color::Black); - for i in 0..graphics.buffer.len() { + for i in 0..graphics.buffer.len() { assert_eq!(graphics.buffer[i], graphics2.buffer[i]); } } @@ -538,15 +530,13 @@ mod graphics { let mut buffer = [Color::White.get_byte_value(); 8]; let mut graphics = Graphics::new(8, 8, &mut buffer); - graphics.draw_line(0, 0, 16, 16, &Color::Black); + graphics.draw_line(0, 0, 16, 16, &Color::Black); - for i in 0..graphics.buffer.len() { + for i in 0..graphics.buffer.len() { assert_eq!(graphics.buffer[i], !(0x80 >> i % 8)); } } - - #[test] fn test_pixel() { let mut buffer = [Color::White.get_byte_value(); 8]; @@ -555,7 +545,6 @@ mod graphics { assert_eq!(graphics.buffer[0], !0x40); - let mut buffer = [Color::White.get_byte_value(); 16]; let mut graphics = Graphics::new(16, 8, &mut buffer); graphics.draw_pixel(9, 0, &Color::Black); @@ -573,15 +562,14 @@ mod graphics { for i in 1..graphics.buffer.len() { assert_eq!(graphics.buffer[i], Color::White.get_byte_value()); - } + } - graphics.draw_byte(0, 0, 0x5A, &Color::Black) ; + graphics.draw_byte(0, 0, 0x5A, &Color::Black); assert_eq!(graphics.buffer[0], !0x5A); } #[test] fn test_char_with_8x8_font() { - // Test ! let mut buffer = [Color::White.get_byte_value(); 8]; let mut graphics = Graphics::new(8, 8, &mut buffer); @@ -592,8 +580,7 @@ mod graphics { } assert_eq!(graphics.buffer[5], Color::White.get_byte_value()); assert_eq!(graphics.buffer[6], !0x20); - assert_eq!(graphics.buffer[7], Color::White.get_byte_value()); - + assert_eq!(graphics.buffer[7], Color::White.get_byte_value()); // Test H let mut buffer = [Color::White.get_byte_value(); 8]; @@ -603,36 +590,34 @@ mod graphics { for i in 0..3 { assert_eq!(graphics.buffer[i], !0x88); } - assert_eq!(graphics.buffer[3], !0xF8); + assert_eq!(graphics.buffer[3], !0xF8); for i in 4..7 { assert_eq!(graphics.buffer[i], !0x88); } - assert_eq!(graphics.buffer[7], Color::White.get_byte_value()); + assert_eq!(graphics.buffer[7], Color::White.get_byte_value()); } #[test] fn test_string_with_8x8_font() { - // Test !H let mut buffer = [Color::White.get_byte_value(); 16]; let mut graphics = Graphics::new(16, 8, &mut buffer); graphics.draw_string_8x8(0, 0, "!H", &Color::Black); for i in 0..5 { - assert_eq!(graphics.buffer[i*2], !0x20); + assert_eq!(graphics.buffer[i * 2], !0x20); } - assert_eq!(graphics.buffer[5*2], Color::White.get_byte_value()); - assert_eq!(graphics.buffer[6*2], !0x20); - assert_eq!(graphics.buffer[7*2], Color::White.get_byte_value()); - + assert_eq!(graphics.buffer[5 * 2], Color::White.get_byte_value()); + assert_eq!(graphics.buffer[6 * 2], !0x20); + assert_eq!(graphics.buffer[7 * 2], Color::White.get_byte_value()); for i in 0..3 { - assert_eq!(graphics.buffer[i*2 + 1], !0x88); + assert_eq!(graphics.buffer[i * 2 + 1], !0x88); } - assert_eq!(graphics.buffer[3*2 + 1], !0xF8); + assert_eq!(graphics.buffer[3 * 2 + 1], !0xF8); for i in 4..7 { - assert_eq!(graphics.buffer[i*2 + 1], !0x88); + assert_eq!(graphics.buffer[i * 2 + 1], !0x88); } - assert_eq!(graphics.buffer[7*2 + 1], Color::White.get_byte_value()); + assert_eq!(graphics.buffer[7 * 2 + 1], Color::White.get_byte_value()); } -} \ No newline at end of file +} diff --git a/src/epd1in54/mod.rs b/src/epd1in54/mod.rs index ccaf7c5..adff9ec 100644 --- a/src/epd1in54/mod.rs +++ b/src/epd1in54/mod.rs @@ -1,5 +1,5 @@ //! A simple Driver for the Waveshare 1.54" E-Ink Display via SPI -//! +//! //! //! # Examples from the 4.2" Display. It should work the same for the 1.54" one. //! @@ -7,15 +7,15 @@ //! let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay).unwrap(); //! //! let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()]; -//! +//! //! // draw something into the buffer -//! +//! //! epd4in2.display_and_transfer_buffer(buffer, None); -//! +//! //! // wait and look at the image -//! +//! //! epd4in2.clear_frame(None); -//! +//! //! epd4in2.sleep(); //! ``` @@ -25,31 +25,18 @@ const HEIGHT: u16 = 200; const DEFAULT_BACKGROUND_COLOR: Color = Color::White; use hal::{ - blocking::{ - spi::Write, - delay::* - }, - digital::* + blocking::{delay::*, spi::Write}, + digital::*, }; -use type_a::{ - LUT_FULL_UPDATE, - LUT_PARTIAL_UPDATE, - command::Command -}; +use type_a::{command::Command, LUT_FULL_UPDATE, LUT_PARTIAL_UPDATE}; use drawing::color::Color; - - - use interface::*; use interface::connection_interface::ConnectionInterface; - - - /// EPD1in54 driver /// pub struct EPD1in54 { @@ -58,33 +45,29 @@ pub struct EPD1in54 { /// EPD (width, height) //epd: EPD, /// Color - background_color: Color, + background_color: Color, } impl EPD1in54 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, DataCommand: OutputPin, RST: OutputPin, - Delay: DelayUs + DelayMs -{ - -} - + Delay: DelayUs + DelayMs, +{} -impl WaveshareInterface +impl WaveshareInterface for EPD1in54 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, DataCommand: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, -{ - +{ fn get_width(&self) -> u16 { WIDTH } @@ -93,23 +76,20 @@ where HEIGHT } - fn new( - interface: ConnectionInterface + interface: ConnectionInterface, ) -> Result { - - let mut epd = EPD1in54 {interface, background_color: DEFAULT_BACKGROUND_COLOR}; + let mut epd = EPD1in54 { + interface, + background_color: DEFAULT_BACKGROUND_COLOR, + }; epd.init()?; Ok(epd) } - - fn init(&mut self) -> Result<(), E> { - - self.reset(); // 3 Databytes: @@ -153,7 +133,6 @@ where } fn sleep(&mut self) -> Result<(), E> { - self.interface.send_command(Command::DEEP_SLEEP_MODE)?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here? @@ -163,7 +142,6 @@ where Ok(()) } - fn reset(&mut self) { self.interface.reset() } @@ -172,9 +150,7 @@ where self.interface.delay_ms(delay) } - - - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E>{ + fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E> { self.use_full_frame()?; self.interface.send_command(Command::WRITE_RAM)?; @@ -182,7 +158,14 @@ where } //TODO: update description: last 3 bits will be ignored for width and x_pos - fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), E>{ + fn update_partial_frame( + &mut self, + buffer: &[u8], + x: u16, + y: u16, + width: u16, + height: u16, + ) -> Result<(), E> { self.set_ram_area(x, y, x + width, y + height)?; self.set_ram_counter(x, y)?; @@ -190,8 +173,7 @@ where self.interface.send_multiple_data(buffer) } - - fn display_frame(&mut self) -> Result<(), E>{ + fn display_frame(&mut self) -> Result<(), E> { // enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version) //TODO: test control_1 or control_2 with default value 0xFF (from the datasheet) self.interface.send_command(Command::DISPLAY_UPDATE_CONTROL_2)?; @@ -203,32 +185,29 @@ where self.interface.send_command(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE) } - - fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>{ + fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E> { self.update_frame(buffer)?; self.display_frame() } - - fn clear_frame(&mut self) -> Result<(), E>{ + fn clear_frame(&mut self) -> Result<(), E> { self.use_full_frame()?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.send_command(Command::WRITE_RAM)?; + self.interface.send_command(Command::WRITE_RAM)?; self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT) } /// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame()) - fn set_background_color(&mut self, background_color: Color){ + fn set_background_color(&mut self, background_color: Color) { self.background_color = background_color; } - } impl EPD1in54 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, @@ -239,21 +218,27 @@ where fn wait_until_idle(&mut self) { self.interface.wait_until_idle(false); } - + pub(crate) fn use_full_frame(&mut self) -> Result<(), E> { // choose full frame/ram self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?; // start from the beginning - self.set_ram_counter(0,0) + self.set_ram_counter(0, 0) } - - pub(crate) fn set_ram_area(&mut self, start_x: u16, start_y: u16, end_x: u16, end_y: u16) -> Result<(), E> { + + pub(crate) fn set_ram_area( + &mut self, + start_x: u16, + start_y: u16, + end_x: u16, + end_y: u16, + ) -> Result<(), E> { assert!(start_x < end_x); assert!(start_y < end_y); // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram - // aren't relevant + // aren't relevant self.interface.send_command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?; self.interface.send_data((start_x >> 3) as u8)?; self.interface.send_data((end_x >> 3) as u8)?; @@ -281,12 +266,12 @@ where Ok(()) } - /// Uses the slower full update + /// Uses the slower full update pub fn set_lut(&mut self) -> Result<(), E> { self.set_lut_helper(&LUT_FULL_UPDATE) } - /// Uses the quick partial refresh + /// Uses the quick partial refresh pub fn set_lut_quick(&mut self) -> Result<(), E> { self.set_lut_helper(&LUT_PARTIAL_UPDATE) } @@ -296,11 +281,9 @@ where // self.set_lut_helper(buffer) //} - fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> { assert!(buffer.len() == 30); self.interface.send_command(Command::WRITE_LUT_REGISTER)?; self.interface.send_multiple_data(buffer) } - -} \ No newline at end of file +} diff --git a/src/epd2in9/mod.rs b/src/epd2in9/mod.rs index d6e74e4..f911e62 100644 --- a/src/epd2in9/mod.rs +++ b/src/epd2in9/mod.rs @@ -1,5 +1,5 @@ //! A simple Driver for the Waveshare 2.9" E-Ink Display via SPI -//! +//! //! //! # Examples from the 4.2" Display. It should work the same for the 2.9" one. //! @@ -7,15 +7,15 @@ //! let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay).unwrap(); //! //! let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()]; -//! +//! //! // draw something into the buffer -//! +//! //! epd4in2.display_and_transfer_buffer(buffer, None); -//! +//! //! // wait and look at the image -//! +//! //! epd4in2.clear_frame(None); -//! +//! //! epd4in2.sleep(); //! ``` @@ -24,32 +24,18 @@ const HEIGHT: u16 = 296; const DEFAULT_BACKGROUND_COLOR: Color = Color::White; use hal::{ - blocking::{ - spi::Write, - delay::* - }, - digital::* + blocking::{delay::*, spi::Write}, + digital::*, }; - -use type_a::{ - LUT_FULL_UPDATE, - LUT_PARTIAL_UPDATE, - command::Command -}; +use type_a::{command::Command, LUT_FULL_UPDATE, LUT_PARTIAL_UPDATE}; use drawing::color::Color; - - - use interface::*; use interface::connection_interface::ConnectionInterface; - - - /// EPD2in9 driver /// pub struct EPD2in9 { @@ -58,33 +44,30 @@ pub struct EPD2in9 { /// EPD (width, height) //epd: EPD, /// Color - background_color: Color, + background_color: Color, } impl EPD2in9 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, DataCommand: OutputPin, RST: OutputPin, - Delay: DelayUs + DelayMs -{ - -} - + Delay: DelayUs + DelayMs, +{} -impl WaveshareInterface +impl + WaveshareInterface for EPD2in9 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, DataCommand: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, -{ - +{ fn get_width(&self) -> u16 { WIDTH } @@ -93,26 +76,23 @@ where HEIGHT } - fn new( - interface: ConnectionInterface + interface: ConnectionInterface, ) -> Result { //let epd = EPD::new(WIDTH, HEIGHT); //let background_color = Color::White; - let mut epd = EPD2in9 {interface, background_color: DEFAULT_BACKGROUND_COLOR}; - + let mut epd = EPD2in9 { + interface, + background_color: DEFAULT_BACKGROUND_COLOR, + }; epd.init()?; Ok(epd) } - - fn init(&mut self) -> Result<(), E> { - - self.reset(); // 3 Databytes: @@ -156,7 +136,6 @@ where } fn sleep(&mut self) -> Result<(), E> { - self.interface.send_command(Command::DEEP_SLEEP_MODE)?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here? @@ -166,7 +145,6 @@ where Ok(()) } - fn reset(&mut self) { self.interface.reset() } @@ -175,9 +153,7 @@ where self.interface.delay_ms(delay) } - - - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E>{ + fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E> { self.use_full_frame()?; self.interface.send_command(Command::WRITE_RAM)?; @@ -185,7 +161,14 @@ where } //TODO: update description: last 3 bits will be ignored for width and x_pos - fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), E>{ + fn update_partial_frame( + &mut self, + buffer: &[u8], + x: u16, + y: u16, + width: u16, + height: u16, + ) -> Result<(), E> { self.set_ram_area(x, y, x + width, y + height)?; self.set_ram_counter(x, y)?; @@ -193,8 +176,7 @@ where self.interface.send_multiple_data(buffer) } - - fn display_frame(&mut self) -> Result<(), E>{ + fn display_frame(&mut self) -> Result<(), E> { // enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version) //TODO: test control_1 or control_2 with default value 0xFF (from the datasheet) self.interface.send_command(Command::DISPLAY_UPDATE_CONTROL_2)?; @@ -206,32 +188,29 @@ where self.interface.send_command(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE) } - - fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>{ + fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E> { self.update_frame(buffer)?; self.display_frame() } - - fn clear_frame(&mut self) -> Result<(), E>{ + fn clear_frame(&mut self) -> Result<(), E> { self.use_full_frame()?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.send_command(Command::WRITE_RAM)?; + self.interface.send_command(Command::WRITE_RAM)?; self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT) } /// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame()) - fn set_background_color(&mut self, background_color: Color){ + fn set_background_color(&mut self, background_color: Color) { self.background_color = background_color; } - } impl EPD2in9 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, @@ -242,21 +221,27 @@ where fn wait_until_idle(&mut self) { self.interface.wait_until_idle(false); } - + pub(crate) fn use_full_frame(&mut self) -> Result<(), E> { // choose full frame/ram self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?; // start from the beginning - self.set_ram_counter(0,0) + self.set_ram_counter(0, 0) } - - pub(crate) fn set_ram_area(&mut self, start_x: u16, start_y: u16, end_x: u16, end_y: u16) -> Result<(), E> { + + pub(crate) fn set_ram_area( + &mut self, + start_x: u16, + start_y: u16, + end_x: u16, + end_y: u16, + ) -> Result<(), E> { assert!(start_x < end_x); assert!(start_y < end_y); // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram - // aren't relevant + // aren't relevant self.interface.send_command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?; self.interface.send_data((start_x >> 3) as u8)?; self.interface.send_data((end_x >> 3) as u8)?; @@ -284,12 +269,12 @@ where Ok(()) } - /// Uses the slower full update + /// Uses the slower full update pub fn set_lut(&mut self) -> Result<(), E> { self.set_lut_helper(&LUT_FULL_UPDATE) } - /// Uses the quick partial refresh + /// Uses the quick partial refresh pub fn set_lut_quick(&mut self) -> Result<(), E> { self.set_lut_helper(&LUT_PARTIAL_UPDATE) } @@ -299,11 +284,9 @@ where // self.set_lut_helper(buffer) //} - fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> { assert!(buffer.len() == 30); self.interface.send_command(Command::WRITE_LUT_REGISTER)?; self.interface.send_multiple_data(buffer) } - -} \ No newline at end of file +} diff --git a/src/epd4in2/command.rs b/src/epd4in2/command.rs index c41b951..75800cf 100644 --- a/src/epd4in2/command.rs +++ b/src/epd4in2/command.rs @@ -1,170 +1,167 @@ //! SPI Commands for the Waveshare 4.2" E-Ink Display use interface; /// EPD4IN2 commands -/// +/// /// Should rarely (never?) be needed directly. -/// -/// For more infos about the addresses and what they are doing look into the pdfs -/// +/// +/// For more infos about the addresses and what they are doing look into the pdfs +/// /// The description of the single commands is mostly taken from IL0398.pdf #[allow(dead_code)] #[allow(non_camel_case_types)] #[derive(Copy, Clone)] pub(crate) enum Command { /// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset - PANEL_SETTING = 0x00, - /// selecting internal and external power - POWER_SETTING = 0x01, - /// After the Power Off command, the driver will power off following the Power Off Sequence. This command will turn off charge - /// pump, T-con, source driver, gate driver, VCOM, and temperature sensor, but register data will be kept until VDD becomes OFF. - /// Source Driver output and Vcom will remain as previous condition, which may have 2 conditions: floating. - POWER_OFF = 0x02, - /// Setting Power OFF sequence - POWER_OFF_SEQUENCE_SETTING = 0x03, - /// Turning On the Power - POWER_ON = 0x04, - /// This command enables the internal bandgap, which will be cleared by the next POF. - POWER_ON_MEASURE = 0x05, - /// Starting data transmission - BOOSTER_SOFT_START = 0x06, - /// After this command is transmitted, the chip would enter the deep-sleep mode to save power. - /// - /// The deep sleep mode would return to standby by hardware reset. - /// - /// The only one parameter is a check code, the command would be excuted if check code = 0xA5. - DEEP_SLEEP = 0x07, - /// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data - /// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel. - /// - /// - In B/W mode, this command writes “OLD” data to SRAM. - /// - In B/W/Red mode, this command writes “B/W” data to SRAM. - /// - In Program mode, this command writes “OTP” data to SRAM for programming. - DATA_START_TRANSMISSION_1 = 0x10, - /// Stopping data transmission - DATA_STOP = 0x11, - /// While user sent this command, driver will refresh display (data/VCOM) according to SRAM data and LUT. - /// - /// After Display Refresh command, BUSY_N signal will become “0” and the refreshing of panel starts. - DISPLAY_REFRESH = 0x12, - /// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data - /// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel. - /// - In B/W mode, this command writes “NEW” data to SRAM. - /// - In B/W/Red mode, this command writes “RED” data to SRAM. - DATA_START_TRANSMISSION_2 = 0x13, + PANEL_SETTING = 0x00, + /// selecting internal and external power + POWER_SETTING = 0x01, + /// After the Power Off command, the driver will power off following the Power Off Sequence. This command will turn off charge + /// pump, T-con, source driver, gate driver, VCOM, and temperature sensor, but register data will be kept until VDD becomes OFF. + /// Source Driver output and Vcom will remain as previous condition, which may have 2 conditions: floating. + POWER_OFF = 0x02, + /// Setting Power OFF sequence + POWER_OFF_SEQUENCE_SETTING = 0x03, + /// Turning On the Power + POWER_ON = 0x04, + /// This command enables the internal bandgap, which will be cleared by the next POF. + POWER_ON_MEASURE = 0x05, + /// Starting data transmission + BOOSTER_SOFT_START = 0x06, + /// After this command is transmitted, the chip would enter the deep-sleep mode to save power. + /// + /// The deep sleep mode would return to standby by hardware reset. + /// + /// The only one parameter is a check code, the command would be excuted if check code = 0xA5. + DEEP_SLEEP = 0x07, + /// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data + /// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel. + /// + /// - In B/W mode, this command writes “OLD” data to SRAM. + /// - In B/W/Red mode, this command writes “B/W” data to SRAM. + /// - In Program mode, this command writes “OTP” data to SRAM for programming. + DATA_START_TRANSMISSION_1 = 0x10, + /// Stopping data transmission + DATA_STOP = 0x11, + /// While user sent this command, driver will refresh display (data/VCOM) according to SRAM data and LUT. + /// + /// After Display Refresh command, BUSY_N signal will become “0” and the refreshing of panel starts. + DISPLAY_REFRESH = 0x12, + /// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data + /// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel. + /// - In B/W mode, this command writes “NEW” data to SRAM. + /// - In B/W/Red mode, this command writes “RED” data to SRAM. + DATA_START_TRANSMISSION_2 = 0x13, - /// This command stores VCOM Look-Up Table with 7 groups of data. Each group contains information for one state and is stored - /// with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_FOR_VCOM = 0x20, - /// This command stores White-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_WHITE_TO_WHITE = 0x21, - /// This command stores Black-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_BLACK_TO_WHITE = 0x22, - /// This command stores White-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_WHITE_TO_BLACK = 0x23, - /// This command stores Black-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_BLACK_TO_BLACK = 0x24, - /// The command controls the PLL clock frequency. - PLL_CONTROL = 0x30, - /// This command reads the temperature sensed by the temperature sensor. - /// - /// Doesn't work! Waveshare doesn't connect the read pin - TEMPERATURE_SENSOR_COMMAND = 0x40, - /// Selects the Internal or External temperature sensor and offset - TEMPERATURE_SENSOR_SELECTION = 0x41, - /// Write External Temperature Sensor - TEMPERATURE_SENSOR_WRITE = 0x42, - /// Read External Temperature Sensor - /// - /// Doesn't work! Waveshare doesn't connect the read pin - TEMPERATURE_SENSOR_READ = 0x43, - /// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync) - VCOM_AND_DATA_INTERVAL_SETTING = 0x50, - /// This command indicates the input power condition. Host can read this flag to learn the battery condition. - LOW_POWER_DETECTION = 0x51, - /// This command defines non-overlap period of Gate and Source. - TCON_SETTING = 0x60, - /// This command defines alternative resolution and this setting is of higher priority than the RES\[1:0\] in R00H (PSR). - RESOLUTION_SETTING = 0x61, - /// This command defines the Fist Active Gate and First Active Source of active channels. - GSST_SETTING = 0x65, - /// The LUT_REV / Chip Revision is read from OTP address = 0x001. - /// - /// Doesn't work! Waveshare doesn't connect the read pin - REVISION = 0x70, - /// Read Flags. This command reads the IC status - /// PTL, I2C_ERR, I2C_BUSY, DATA, PON, POF, BUSY - /// - /// Doesn't work! Waveshare doesn't connect the read pin - GET_STATUS = 0x71, - /// Automatically measure VCOM. This command reads the IC status - AUTO_MEASUREMENT_VCOM = 0x80, - /// This command gets the VCOM value - /// - /// Doesn't work! Waveshare doesn't connect the read pin - READ_VCOM_VALUE = 0x81, - /// Set VCM_DC - VCM_DC_SETTING = 0x82, - /// This command sets partial window - PARTIAL_WINDOW = 0x90, - /// This command makes the display enter partial mode - PARTIAL_IN = 0x91, - /// This command makes the display exit partial mode and enter normal mode - PARTIAL_OUT = 0x92, - /// After this command is issued, the chip would enter the program mode. - /// - /// After the programming procedure completed, a hardware reset is necessary for leaving program mode. - /// - /// The only one parameter is a check code, the command would be excuted if check code = 0xA5. - PROGRAM_MODE = 0xA0, - /// After this command is transmitted, the programming state machine would be activated. - /// - /// The BUSY flag would fall to 0 until the programming is completed. - ACTIVE_PROGRAMMING = 0xA1, - /// The command is used for reading the content of OTP for checking the data of programming. - /// - /// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF. - READ_OTP = 0xA2, - /// This command is set for saving power during fresh period. If the output voltage of VCOM / Source is from negative to positive or - /// from positive to negative, the power saving mechanism will be activated. The active period width is defined by the following two - /// parameters. - POWER_SAVING = 0xE3, + /// This command stores VCOM Look-Up Table with 7 groups of data. Each group contains information for one state and is stored + /// with 6 bytes, while the sixth byte indicates how many times that phase will repeat. + /// + /// from IL0373 + LUT_FOR_VCOM = 0x20, + /// This command stores White-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is + /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. + /// + /// from IL0373 + LUT_WHITE_TO_WHITE = 0x21, + /// This command stores Black-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is + /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. + /// + /// from IL0373 + LUT_BLACK_TO_WHITE = 0x22, + /// This command stores White-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is + /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. + /// + /// from IL0373 + LUT_WHITE_TO_BLACK = 0x23, + /// This command stores Black-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is + /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. + /// + /// from IL0373 + LUT_BLACK_TO_BLACK = 0x24, + /// The command controls the PLL clock frequency. + PLL_CONTROL = 0x30, + /// This command reads the temperature sensed by the temperature sensor. + /// + /// Doesn't work! Waveshare doesn't connect the read pin + TEMPERATURE_SENSOR_COMMAND = 0x40, + /// Selects the Internal or External temperature sensor and offset + TEMPERATURE_SENSOR_SELECTION = 0x41, + /// Write External Temperature Sensor + TEMPERATURE_SENSOR_WRITE = 0x42, + /// Read External Temperature Sensor + /// + /// Doesn't work! Waveshare doesn't connect the read pin + TEMPERATURE_SENSOR_READ = 0x43, + /// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync) + VCOM_AND_DATA_INTERVAL_SETTING = 0x50, + /// This command indicates the input power condition. Host can read this flag to learn the battery condition. + LOW_POWER_DETECTION = 0x51, + /// This command defines non-overlap period of Gate and Source. + TCON_SETTING = 0x60, + /// This command defines alternative resolution and this setting is of higher priority than the RES\[1:0\] in R00H (PSR). + RESOLUTION_SETTING = 0x61, + /// This command defines the Fist Active Gate and First Active Source of active channels. + GSST_SETTING = 0x65, + /// The LUT_REV / Chip Revision is read from OTP address = 0x001. + /// + /// Doesn't work! Waveshare doesn't connect the read pin + REVISION = 0x70, + /// Read Flags. This command reads the IC status + /// PTL, I2C_ERR, I2C_BUSY, DATA, PON, POF, BUSY + /// + /// Doesn't work! Waveshare doesn't connect the read pin + GET_STATUS = 0x71, + /// Automatically measure VCOM. This command reads the IC status + AUTO_MEASUREMENT_VCOM = 0x80, + /// This command gets the VCOM value + /// + /// Doesn't work! Waveshare doesn't connect the read pin + READ_VCOM_VALUE = 0x81, + /// Set VCM_DC + VCM_DC_SETTING = 0x82, + /// This command sets partial window + PARTIAL_WINDOW = 0x90, + /// This command makes the display enter partial mode + PARTIAL_IN = 0x91, + /// This command makes the display exit partial mode and enter normal mode + PARTIAL_OUT = 0x92, + /// After this command is issued, the chip would enter the program mode. + /// + /// After the programming procedure completed, a hardware reset is necessary for leaving program mode. + /// + /// The only one parameter is a check code, the command would be excuted if check code = 0xA5. + PROGRAM_MODE = 0xA0, + /// After this command is transmitted, the programming state machine would be activated. + /// + /// The BUSY flag would fall to 0 until the programming is completed. + ACTIVE_PROGRAMMING = 0xA1, + /// The command is used for reading the content of OTP for checking the data of programming. + /// + /// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF. + READ_OTP = 0xA2, + /// This command is set for saving power during fresh period. If the output voltage of VCOM / Source is from negative to positive or + /// from positive to negative, the power saving mechanism will be activated. The active period width is defined by the following two + /// parameters. + POWER_SAVING = 0xE3, } - - impl interface::Command for Command { - /// Returns the address of the command - fn address(self) -> u8 { - self as u8 - } + /// Returns the address of the command + fn address(self) -> u8 { + self as u8 + } } - #[cfg(test)] mod tests { use super::*; - use interface::Command as CommandTrait; + use interface::Command as CommandTrait; #[test] fn command_addr() { - assert_eq!(Command::POWER_SAVING.address(), 0xE3); + assert_eq!(Command::POWER_SAVING.address(), 0xE3); - assert_eq!(Command::PANEL_SETTING.address(), 0x00); + assert_eq!(Command::PANEL_SETTING.address(), 0x00); - assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12); + assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12); } -} \ No newline at end of file +} diff --git a/src/epd4in2/constants.rs b/src/epd4in2/constants.rs index cc866cf..47ec396 100644 --- a/src/epd4in2/constants.rs +++ b/src/epd4in2/constants.rs @@ -108,4 +108,4 @@ pub(crate) const LUT_WB_QUICK: [u8; 42] =[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; \ No newline at end of file +]; diff --git a/src/epd4in2/mod.rs b/src/epd4in2/mod.rs index e3f5b78..006294f 100644 --- a/src/epd4in2/mod.rs +++ b/src/epd4in2/mod.rs @@ -62,11 +62,9 @@ use drawing::color::Color; pub mod command; use self::command::Command; - /// EPD4in2 driver /// -pub struct EPD4in2 - { +pub struct EPD4in2 { /// Connection Interface interface: ConnectionInterface, /// Width @@ -77,11 +75,10 @@ pub struct EPD4in2 color: Color, } - - -impl WaveshareInterface +impl + WaveshareInterface for EPD4in2 -where +where SPI: Write, CS: OutputPin, BUSY: InputPin, @@ -116,7 +113,6 @@ where let width = WIDTH as u16; let height = HEIGHT as u16; - let color = Color::White; let mut epd = EPD4in2 { interface, @@ -227,7 +223,7 @@ where self.send_command(Command::DATA_START_TRANSMISSION_2)?; //self.send_multiple_data(buffer)?; - + for &elem in buffer.iter() { self.send_data(elem)?; } @@ -243,7 +239,6 @@ where width: u16, height: u16, ) -> Result<(), SpiError> { - if buffer.len() as u16 != width / 8 * height { //TODO: panic!! or sth like that //return Err("Wrong buffersize"); @@ -279,12 +274,11 @@ where self.send_command(Command::PARTIAL_OUT) } - fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError>{ + fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError> { self.update_frame(buffer)?; self.display_frame() } - fn display_frame(&mut self) -> Result<(), SpiError> { self.send_command(Command::DISPLAY_REFRESH)?; @@ -366,8 +360,8 @@ where } /// Fill the look-up table for a quick display (partial refresh) - /// - /// Is automatically done by [EPD4in2::display_frame_quick()](EPD4in2::display_frame_quick()) + /// + /// Is automatically done by [EPD4in2::display_frame_quick()](EPD4in2::display_frame_quick()) /// //TODO: make public? #[cfg(feature = "epd4in2_fast_update")] fn set_lut_quick(&mut self) -> Result<(), SpiError> { diff --git a/src/interface/connection_interface.rs b/src/interface/connection_interface.rs index 361937a..92b0dd3 100644 --- a/src/interface/connection_interface.rs +++ b/src/interface/connection_interface.rs @@ -1,9 +1,6 @@ use hal::{ - blocking::{ - spi::Write, - delay::* - }, - digital::* + blocking::{delay::*, spi::Write}, + digital::*, }; use interface::Command; @@ -25,9 +22,9 @@ pub struct ConnectionInterface { delay: D, } - -impl ConnectionInterface -where +impl + ConnectionInterface +where SPI: Write, CS: OutputPin, BUSY: InputPin, @@ -36,47 +33,54 @@ where Delay: DelayUs + DelayMs, { pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DataCommand, rst: RST, delay: Delay) -> Self { - ConnectionInterface {spi, cs, busy, dc, rst, delay } + ConnectionInterface { + spi, + cs, + busy, + dc, + rst, + delay, + } } - - /// Basic function for sending [Commands](Command). - /// + + /// Basic function for sending [Commands](Command). + /// /// Enables direct interaction with the device with the help of [send_data()](ConnectionInterface::send_data()) /// Should rarely be needed! - /// //TODO: make public? + /// //TODO: make public? pub(crate) fn send_command(&mut self, command: T) -> Result<(), ErrorSpeziale> { // low for commands - self.dc.set_low(); + self.dc.set_low(); // Transfer the command over spi - self.with_cs(|epd| { - epd.spi.write(&[command.address()]) - }) + self.with_cs(|epd| epd.spi.write(&[command.address()])) } /// Basic function for sending a single u8 of data over spi - /// + /// /// Enables direct interaction with the device with the help of [Esend_command()](ConnectionInterface::send_command()) - /// + /// /// Should rarely be needed! - /// //TODO: make public? + /// //TODO: make public? pub(crate) fn send_data(&mut self, val: u8) -> Result<(), ErrorSpeziale> { // high for data self.dc.set_high(); // Transfer data (u8) over spi - self.with_cs(|epd| { - epd.spi.write(&[val]) - }) + self.with_cs(|epd| epd.spi.write(&[val])) } /// Basic function for sending a single u8 of data over spi - /// + /// /// Enables direct interaction with the device with the help of [Esend_command()](ConnectionInterface::send_command()) - /// + /// /// Should rarely be needed! - /// //TODO: make public? - pub(crate) fn send_data_x_times(&mut self, val: u8, repetitions: u16) -> Result<(), ErrorSpeziale> { + /// //TODO: make public? + pub(crate) fn send_data_x_times( + &mut self, + val: u8, + repetitions: u16, + ) -> Result<(), ErrorSpeziale> { // high for data self.dc.set_high(); @@ -85,29 +89,27 @@ where for _ in 0..repetitions { epd.spi.write(&[val])?; } - Ok(()) + Ok(()) }) } /// Basic function for sending an array of u8-values of data over spi - /// + /// /// Enables direct interaction with the device with the help of [send_command()](EPD4in2::send_command()) - /// + /// /// Should rarely be needed! - /// //TODO: make public? + /// //TODO: make public? pub(crate) fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), ErrorSpeziale> { // high for data self.dc.set_high(); // Transfer data (u8-array) over spi - self.with_cs(|epd| { - epd.spi.write(data) - }) + self.with_cs(|epd| epd.spi.write(data)) } // spi write helper/abstraction function pub(crate) fn with_cs(&mut self, f: F) -> Result<(), ErrorSpeziale> - where + where F: FnOnce(&mut Self) -> Result<(), ErrorSpeziale>, { // activate spi with cs low @@ -120,18 +122,17 @@ where result } - /// Waits until device isn't busy anymore (busy == HIGH) - /// + /// /// This is normally handled by the more complicated commands themselves, /// but in the case you send data and commands directly you might need to check /// if the device is still busy - /// + /// /// is_busy_low - /// + /// /// - TRUE for epd4in2, epd2in13, epd2in7, epd5in83, epd7in5 /// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?) - /// + /// /// Most likely there was a mistake with the 2in9 busy connection pub(crate) fn wait_until_idle(&mut self, is_busy_low: bool) { self.delay_ms(1); @@ -142,18 +143,17 @@ where } } - /// Abstraction of setting the delay for simpler calls - /// + /// /// maximum delay ~65 seconds (u16:max in ms) pub(crate) fn delay_ms(&mut self, delay: u16) { self.delay.delay_ms(delay); } /// Resets the device. - /// + /// /// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep()) - /// + /// /// TODO: Takes at least 400ms of delay alone, can it be shortened? pub(crate) fn reset(&mut self) { self.rst.set_low(); @@ -166,5 +166,4 @@ where //TODO: same as 3 lines above self.delay_ms(200); } - -} \ No newline at end of file +} diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 31f9ff7..8b29d9a 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -1,11 +1,8 @@ +use core::marker::Sized; use hal::{ - blocking::{ - spi::Write, - delay::* - }, - digital::* + blocking::{delay::*, spi::Write}, + digital::*, }; -use core::marker::Sized; use drawing::color::Color; @@ -13,16 +10,12 @@ use drawing::color::Color; pub mod connection_interface; use self::connection_interface::ConnectionInterface; - /// All commands need to have this trait which gives the address of the command /// which needs to be send via SPI with activated CommandsPin (Data/Command Pin in CommandMode) pub(crate) trait Command { fn address(self) -> u8; } - - - //TODO: add LUT trait with set_fast_lut and set_manual_lut and set_normal_lut or sth like that? // for partial updates trait LUTSupport { @@ -31,15 +24,14 @@ trait LUTSupport { fn set_lut_manual(&mut self, data: &[u8]) -> Result<(), Error>; } - pub trait WaveshareInterface - where - SPI: Write, - CS: OutputPin, - BUSY: InputPin, - DataCommand: OutputPin, - RST: OutputPin, - Delay: DelayUs + DelayMs, +where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DataCommand: OutputPin, + RST: OutputPin, + Delay: DelayUs + DelayMs, { /// Get the width of the display fn get_width(&self) -> u16; @@ -48,37 +40,44 @@ pub trait WaveshareInterface fn get_height(&self) -> u16; /// Creates a new driver from a SPI peripheral, CS Pin, Busy InputPin, DC - /// + /// /// This already initialises the device. That means [init()](WaveshareInterface::init()) isn't needed directly afterwards fn new( - interface: ConnectionInterface + interface: ConnectionInterface, ) -> Result - where Self: Sized; + where + Self: Sized; /// This initialises the EPD and powers it up - /// + /// /// This function is already called from [new()](WaveshareInterface::new()) - /// + /// /// This function calls [reset()](WaveshareInterface::reset()), /// so you don't need to call reset your self when trying to wake your device up /// after setting it to sleep. fn init(&mut self) -> Result<(), Error>; - // void DisplayFrame(const unsigned char* frame_buffer); /// Transmit a full frame to the SRAM of the DPD - /// + /// fn update_frame(&mut self, buffer: &[u8]) -> Result<(), Error>; //TODO: is dtm always used? /// Transmit partial data to the SRAM of the EPD, /// the final parameter dtm chooses between the 2 - /// internal buffers - /// + /// internal buffers + /// /// Normally it should be dtm2, so use false - /// + /// /// BUFFER needs to be of size: w / 8 * l ! - fn update_partial_frame(&mut self, buffer: &[u8], x: u16, y: u16, width: u16, height: u16) -> Result<(), Error>; + fn update_partial_frame( + &mut self, + buffer: &[u8], + x: u16, + y: u16, + width: u16, + height: u16, + ) -> Result<(), Error>; /// Displays the frame data from SRAM fn display_frame(&mut self) -> Result<(), Error>; @@ -87,29 +86,28 @@ pub trait WaveshareInterface fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), Error>; /// Clears the frame from the buffer - /// + /// /// Uses the chosen background color fn clear_frame(&mut self) -> Result<(), Error>; /// Sets the backgroundcolor for various commands like [clear_frame()](WaveshareInterface::clear_frame()) fn set_background_color(&mut self, color: Color); - - /// Let the device enter deep-sleep mode to save power. - /// - /// The deep sleep mode returns to standby with a hardware reset. + /// Let the device enter deep-sleep mode to save power. + /// + /// The deep sleep mode returns to standby with a hardware reset. /// But you can also use [reset()](WaveshareInterface::reset()) to awaken. /// But as you need to power it up once more anyway you can also just directly use [init()](WaveshareInterface::init()) for resetting /// and initialising which already contains the reset fn sleep(&mut self) -> Result<(), Error>; /// Resets the device. - /// + /// /// Often used to awake the module from deep sleep. See [sleep()](WaveshareInterface::sleep()) fn reset(&mut self); /// Abstraction of setting the delay for simpler calls - /// + /// /// maximum delay ~65 seconds (u16:max in ms) fn delay_ms(&mut self, delay: u16); -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 814f104..cb4f661 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,86 +3,79 @@ //! This driver was built using [`embedded-hal`] traits. //! //! [`embedded-hal`]: https://docs.rs/embedded-hal/~0.1 -//! +//! //! # Requirements -//! +//! //! ### SPI -//! +//! //! - MISO is not connected/available //! - SPI_MODE_0 is used (CPHL = 0, CPOL = 0) //! - 8 bits per word, MSB first //! - Max. Speed tested was 8Mhz but more should be possible -//! +//! //! ### Other.... -//! -//! - Buffersize: Wherever a buffer is used it always needs to be of the size: `width / 8 * length`, +//! +//! - Buffersize: Wherever a buffer is used it always needs to be of the size: `width / 8 * length`, //! where width and length being either the full e-ink size or the partial update window size //! //! # Examples //! //! ```ignore //! use eink-waveshare-rs::epd4in2::EPD4in2; -//! +//! //! let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay).unwrap(); //! //! let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()]; -//! +//! //! // draw something into the buffer -//! +//! //! epd4in2.display_and_transfer_buffer(buffer, None); -//! +//! //! // wait and look at the image -//! +//! //! epd4in2.clear_frame(None); -//! +//! //! epd4in2.sleep(); //! ``` -//! +//! //! #![no_std] //TODO: Make more assertions about buffersizes? - extern crate embedded_hal as hal; -use hal::{ - spi::{Mode, Phase, Polarity}, -}; +use hal::spi::{Mode, Phase, Polarity}; pub mod drawing; mod interface; -pub use interface::{ - WaveshareInterface, - connection_interface::ConnectionInterface}; +pub use interface::{connection_interface::ConnectionInterface, WaveshareInterface}; -#[cfg(feature="epd4in2")] +#[cfg(feature = "epd4in2")] mod epd4in2; -#[cfg(feature="epd4in2")] +#[cfg(feature = "epd4in2")] pub use epd4in2::EPD4in2; -#[cfg(feature="epd1in54")] +#[cfg(feature = "epd1in54")] mod epd1in54; -#[cfg(feature="epd1in54")] +#[cfg(feature = "epd1in54")] pub use epd1in54::EPD1in54; - -#[cfg(feature="epd2in9")] +#[cfg(feature = "epd2in9")] mod epd2in9; ///2in9 eink -#[cfg(feature="epd2in9")] +#[cfg(feature = "epd2in9")] ///2in9 eink pub use epd2in9::EPD2in9; -#[cfg(any(feature="epd1in54", feature="epd2in9"))] +#[cfg(any(feature = "epd1in54", feature = "epd2in9"))] pub mod type_a; - //TODO: test spi mode -/// SPI mode - +/// SPI mode - /// For more infos see [Requirements: SPI](index.html#spi) pub const SPI_MODE: Mode = Mode { phase: Phase::CaptureOnFirstTransition, polarity: Polarity::IdleLow, -}; \ No newline at end of file +}; diff --git a/src/type_a/command.rs b/src/type_a/command.rs index 4adf5a7..bfe3714 100644 --- a/src/type_a/command.rs +++ b/src/type_a/command.rs @@ -2,97 +2,93 @@ use interface; - /// EPD1in54 and EPD2IN9 commands -/// +/// /// Should rarely (never?) be needed directly. -/// -/// For more infos about the addresses and what they are doing look into the pdfs +/// +/// For more infos about the addresses and what they are doing look into the pdfs #[allow(dead_code)] #[allow(non_camel_case_types)] #[derive(Copy, Clone)] pub(crate) enum Command { - /// Driver Output control - /// 3 Databytes: - /// A[7:0] - /// 0.. A[8] - /// 0.. B[2:0] - /// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0 - DRIVER_OUTPUT_CONTROL = 0x01, - /// Booster Soft start control - /// 3 Databytes: - /// 1.. A[6:0] - /// 1.. B[6:0] - /// 1.. C[6:0] - /// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D - BOOSTER_SOFT_START_CONTROL = 0x0C, + /// Driver Output control + /// 3 Databytes: + /// A[7:0] + /// 0.. A[8] + /// 0.. B[2:0] + /// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0 + DRIVER_OUTPUT_CONTROL = 0x01, + /// Booster Soft start control + /// 3 Databytes: + /// 1.. A[6:0] + /// 1.. B[6:0] + /// 1.. C[6:0] + /// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D + BOOSTER_SOFT_START_CONTROL = 0x0C, GATE_SCAN_START_POSITION = 0x0F, - //TODO: useful? - // GATE_SCAN_START_POSITION = 0x0F, - /// Deep Sleep Mode Control - /// 1 Databyte: - /// 0.. A[0] - /// Values: - /// A[0] = 0: Normal Mode (POR) - /// A[0] = 1: Enter Deep Sleep Mode - DEEP_SLEEP_MODE = 0x10, - // /// Data Entry mode setting - DATA_ENTRY_MODE_SETTING = 0x11, + //TODO: useful? + // GATE_SCAN_START_POSITION = 0x0F, + /// Deep Sleep Mode Control + /// 1 Databyte: + /// 0.. A[0] + /// Values: + /// A[0] = 0: Normal Mode (POR) + /// A[0] = 1: Enter Deep Sleep Mode + DEEP_SLEEP_MODE = 0x10, + // /// Data Entry mode setting + DATA_ENTRY_MODE_SETTING = 0x11, - SW_RESET = 0x12, + SW_RESET = 0x12, - TEMPERATURE_SENSOR_CONTROL = 0x1A, + TEMPERATURE_SENSOR_CONTROL = 0x1A, - MASTER_ACTIVATION = 0x20, + MASTER_ACTIVATION = 0x20, - DISPLAY_UPDATE_CONTROL_1 = 0x21, + DISPLAY_UPDATE_CONTROL_1 = 0x21, - DISPLAY_UPDATE_CONTROL_2 = 0x22, + DISPLAY_UPDATE_CONTROL_2 = 0x22, - WRITE_RAM = 0x24, + WRITE_RAM = 0x24, - WRITE_VCOM_REGISTER = 0x2C, + WRITE_VCOM_REGISTER = 0x2C, - WRITE_LUT_REGISTER = 0x32, + WRITE_LUT_REGISTER = 0x32, - SET_DUMMY_LINE_PERIOD = 0x3A, + SET_DUMMY_LINE_PERIOD = 0x3A, - SET_GATE_LINE_WIDTH = 0x3B, + SET_GATE_LINE_WIDTH = 0x3B, - BORDER_WAVEFORM_CONTROL = 0x3C, + BORDER_WAVEFORM_CONTROL = 0x3C, - SET_RAM_X_ADDRESS_START_END_POSITION = 0x44, + SET_RAM_X_ADDRESS_START_END_POSITION = 0x44, - SET_RAM_Y_ADDRESS_START_END_POSITION = 0x45, + SET_RAM_Y_ADDRESS_START_END_POSITION = 0x45, - SET_RAM_X_ADDRESS_COUNTER = 0x4E, + SET_RAM_X_ADDRESS_COUNTER = 0x4E, - SET_RAM_Y_ADDRESS_COUNTER = 0x4F, + SET_RAM_Y_ADDRESS_COUNTER = 0x4F, - TERMINATE_COMMANDS_AND_FRAME_WRITE = 0xFF + TERMINATE_COMMANDS_AND_FRAME_WRITE = 0xFF, } - - impl interface::Command for Command { - /// Returns the address of the command - fn address(self) -> u8 { - self as u8 - } + /// Returns the address of the command + fn address(self) -> u8 { + self as u8 + } } - #[cfg(test)] mod tests { use super::Command; - use interface::Command as CommandTrait; + use interface::Command as CommandTrait; #[test] fn command_addr() { - assert_eq!(Command::DRIVER_OUTPUT_CONTROL.address(), 0x01); + assert_eq!(Command::DRIVER_OUTPUT_CONTROL.address(), 0x01); - assert_eq!(Command::SET_RAM_X_ADDRESS_COUNTER.address(), 0x4E); + assert_eq!(Command::SET_RAM_X_ADDRESS_COUNTER.address(), 0x4E); - assert_eq!(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE.address(), 0xFF); + assert_eq!(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE.address(), 0xFF); } -} \ No newline at end of file +}