From f7890b5ca5b43ae517d8b4b4920c10b4889c4da2 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Sun, 19 Apr 2020 13:40:52 +0200 Subject: [PATCH 1/4] Attempt to print to device --- lvgl/Cargo.toml | 5 +- lvgl/src/display.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/lvgl/Cargo.toml b/lvgl/Cargo.toml index f1e3bf2..db865c1 100644 --- a/lvgl/Cargo.toml +++ b/lvgl/Cargo.toml @@ -13,5 +13,6 @@ keywords = ["littlevgl", "lvgl", "graphical_interfaces"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -lvgl-sys = {path="../lvgl-sys", version="0.1.1"} -cty = "0.2.1" +lvgl-sys = {path="../lvgl-sys", version="0.1"} +cty = "0.2" +embedded-graphics = "0.6" diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 43dea41..787325a 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -1,5 +1,115 @@ use crate::objx::ObjectX; use core::ptr; +use embedded_graphics; +use embedded_graphics::prelude::*; +use embedded_graphics::{drawable, DrawTarget}; +use core::mem::MaybeUninit; +use embedded_graphics::pixelcolor::{PixelColor, raw::RawData, raw::RawU32}; +use core::marker::PhantomData; + + +struct DisplayDriver + where + F: FnMut(drawable::Pixel), + C: PixelColor +{ + pub raw: lvgl_sys::lv_disp_drv_t, + callback: F, + display_buffer: MaybeUninit, + refresh_buffer: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10], + phantom: PhantomData, +} + +impl DisplayDriver where + F: FnMut(drawable::Pixel), + C: PixelColor { + + pub fn new(mut device: T) -> Self + where + T: DrawTarget + { + let mut callback = move |pixel: drawable::Pixel| { + let _ = device.draw_pixel(pixel); + }; + + // Create a display buffer for LittlevGL + let mut display_buffer = MaybeUninit::::uninit(); + // Declare a buffer for 10 lines + let mut refresh_buffer: [MaybeUninit; + lvgl_sys::LV_HOR_RES_MAX as usize * 10] = + unsafe { MaybeUninit::uninit().assume_init() }; + // Initialize the display buffer + unsafe { + lvgl_sys::lv_disp_buf_init( + display_buffer.as_mut_ptr(), + refresh_buffer.as_mut_ptr() as *mut cty::c_void, + core::ptr::null_mut(), + (lvgl_sys::LV_HOR_RES_MAX * 10) as u32, + ); + } + let mut disp_drv = unsafe { + // Descriptor of a display driver + let mut disp_drv = MaybeUninit::::uninit().assume_init(); + // Basic initialization + lvgl_sys::lv_disp_drv_init(&mut disp_drv); + // Set your driver function + disp_drv.flush_cb = Some(display_callback_wrapper::); + disp_drv.user_data = &mut callback as *mut _ as *mut cty::c_void; + disp_drv + }; + // Assign the buffer to the display + disp_drv.buffer = display_buffer.as_mut_ptr(); + // Finally register the driver + unsafe { + lvgl_sys::lv_disp_drv_register(&mut disp_drv); + } + Self { + raw: disp_drv, + callback, + display_buffer, + refresh_buffer, + phantom: PhantomData, + } + } + + fn get_active_screen(&mut self) -> ObjectX<'static> { + get_active_screen() + } +} + +unsafe extern "C" fn display_callback_wrapper( + disp_drv: *mut lvgl_sys::lv_disp_drv_t, + area: *const lvgl_sys::lv_area_t, + color_p: *mut lvgl_sys::lv_color_t, +) where + F: FnMut(drawable::Pixel), + C: PixelColor +{ + // We need to make sure panics can't escape across the FFI boundary. + //let _ = panic::catch_unwind(|| { + let mut i = 0; + let disp = *disp_drv; + + // Rust code closure reference + let closure = &mut *(disp.user_data as *mut F); + + for y in (*area).y1..=(*area).y2 { + for x in (*area).x1..=(*area).x2 { + // Convert C color representation to high-level Rust + let raw_color = *color_p.add(i); + // let color = Rgb888::new(raw_color.ch.red, + // raw_color.ch.green, + // raw_color.ch.blue); + let color = C::Raw::from_u32(raw_color.full); + i = i + 1; + // Callback the Rust closure to flush the new points to the screen + closure(drawable::Pixel(Point::new(x as i32, y as i32), color)); + } + } + // Indicate to LittlevGL that you are ready with the flushing + lvgl_sys::lv_disp_flush_ready(disp_drv); + //}); // end of panic::catch_unwind +} pub fn get_active_screen() -> ObjectX<'static> { let raw = -- 2.34.1 From 0ddd716735193e2ceeb30da9874b961aa036b7e3 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Sun, 19 Apr 2020 14:17:55 +0200 Subject: [PATCH 2/4] Send device as data --- lvgl/src/display.rs | 47 +++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 787325a..15b5d1b 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -4,34 +4,27 @@ use embedded_graphics; use embedded_graphics::prelude::*; use embedded_graphics::{drawable, DrawTarget}; use core::mem::MaybeUninit; -use embedded_graphics::pixelcolor::{PixelColor, raw::RawData, raw::RawU32}; +use embedded_graphics::pixelcolor::PixelColor; use core::marker::PhantomData; -struct DisplayDriver +struct DisplayDriver<'a, T, C> where - F: FnMut(drawable::Pixel), + T: DrawTarget, C: PixelColor { pub raw: lvgl_sys::lv_disp_drv_t, - callback: F, display_buffer: MaybeUninit, refresh_buffer: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10], - phantom: PhantomData, + phantom: &'a PhantomData, + phantom1: PhantomData, } -impl DisplayDriver where - F: FnMut(drawable::Pixel), - C: PixelColor { - - pub fn new(mut device: T) -> Self - where - T: DrawTarget - { - let mut callback = move |pixel: drawable::Pixel| { - let _ = device.draw_pixel(pixel); - }; - +impl<'a, T, C> DisplayDriver<'a, T, C> where + T: DrawTarget, + C: PixelColor +{ + pub fn new(device: &'a mut T) -> Self { // Create a display buffer for LittlevGL let mut display_buffer = MaybeUninit::::uninit(); // Declare a buffer for 10 lines @@ -53,8 +46,8 @@ impl DisplayDriver where // Basic initialization lvgl_sys::lv_disp_drv_init(&mut disp_drv); // Set your driver function - disp_drv.flush_cb = Some(display_callback_wrapper::); - disp_drv.user_data = &mut callback as *mut _ as *mut cty::c_void; + disp_drv.flush_cb = Some(display_callback_wrapper::); + disp_drv.user_data = device as *mut _ as *mut cty::c_void; disp_drv }; // Assign the buffer to the display @@ -65,10 +58,10 @@ impl DisplayDriver where } Self { raw: disp_drv, - callback, display_buffer, refresh_buffer, - phantom: PhantomData, + phantom: &PhantomData, + phantom1: PhantomData, } } @@ -77,12 +70,12 @@ impl DisplayDriver where } } -unsafe extern "C" fn display_callback_wrapper( +unsafe extern "C" fn display_callback_wrapper( disp_drv: *mut lvgl_sys::lv_disp_drv_t, area: *const lvgl_sys::lv_area_t, color_p: *mut lvgl_sys::lv_color_t, ) where - F: FnMut(drawable::Pixel), + T: DrawTarget, C: PixelColor { // We need to make sure panics can't escape across the FFI boundary. @@ -91,19 +84,15 @@ unsafe extern "C" fn display_callback_wrapper( let disp = *disp_drv; // Rust code closure reference - let closure = &mut *(disp.user_data as *mut F); + let device = &mut *(disp.user_data as *mut T); for y in (*area).y1..=(*area).y2 { for x in (*area).x1..=(*area).x2 { // Convert C color representation to high-level Rust let raw_color = *color_p.add(i); - // let color = Rgb888::new(raw_color.ch.red, - // raw_color.ch.green, - // raw_color.ch.blue); - let color = C::Raw::from_u32(raw_color.full); i = i + 1; // Callback the Rust closure to flush the new points to the screen - closure(drawable::Pixel(Point::new(x as i32, y as i32), color)); + let _ = device.draw_pixel(drawable::Pixel(Point::new(x as i32, y as i32), raw_color.into())); } } // Indicate to LittlevGL that you are ready with the flushing -- 2.34.1 From 5f7bf51fd511d27fd39337c14950652e59276ece Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Sun, 19 Apr 2020 14:51:29 +0200 Subject: [PATCH 3/4] Specific color mode --- lvgl/src/display.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 15b5d1b..7fdc0da 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -4,25 +4,22 @@ use embedded_graphics; use embedded_graphics::prelude::*; use embedded_graphics::{drawable, DrawTarget}; use core::mem::MaybeUninit; -use embedded_graphics::pixelcolor::PixelColor; +use embedded_graphics::pixelcolor::Rgb888; use core::marker::PhantomData; -struct DisplayDriver<'a, T, C> +struct DisplayDriver<'a, T> where - T: DrawTarget, - C: PixelColor + T: DrawTarget, { pub raw: lvgl_sys::lv_disp_drv_t, display_buffer: MaybeUninit, refresh_buffer: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10], phantom: &'a PhantomData, - phantom1: PhantomData, } -impl<'a, T, C> DisplayDriver<'a, T, C> where - T: DrawTarget, - C: PixelColor +impl<'a, T> DisplayDriver<'a, T> where + T: DrawTarget { pub fn new(device: &'a mut T) -> Self { // Create a display buffer for LittlevGL @@ -46,7 +43,7 @@ impl<'a, T, C> DisplayDriver<'a, T, C> where // Basic initialization lvgl_sys::lv_disp_drv_init(&mut disp_drv); // Set your driver function - disp_drv.flush_cb = Some(display_callback_wrapper::); + disp_drv.flush_cb = Some(display_callback_wrapper::); disp_drv.user_data = device as *mut _ as *mut cty::c_void; disp_drv }; @@ -61,7 +58,6 @@ impl<'a, T, C> DisplayDriver<'a, T, C> where display_buffer, refresh_buffer, phantom: &PhantomData, - phantom1: PhantomData, } } @@ -70,13 +66,12 @@ impl<'a, T, C> DisplayDriver<'a, T, C> where } } -unsafe extern "C" fn display_callback_wrapper( +unsafe extern "C" fn display_callback_wrapper( disp_drv: *mut lvgl_sys::lv_disp_drv_t, area: *const lvgl_sys::lv_area_t, color_p: *mut lvgl_sys::lv_color_t, ) where - T: DrawTarget, - C: PixelColor + T: DrawTarget, { // We need to make sure panics can't escape across the FFI boundary. //let _ = panic::catch_unwind(|| { @@ -91,8 +86,9 @@ unsafe extern "C" fn display_callback_wrapper( // Convert C color representation to high-level Rust let raw_color = *color_p.add(i); i = i + 1; + let color = Rgb888::new(raw_color.ch.red, raw_color.ch.green, raw_color.ch.blue); // Callback the Rust closure to flush the new points to the screen - let _ = device.draw_pixel(drawable::Pixel(Point::new(x as i32, y as i32), raw_color.into())); + let _ = device.draw_pixel(drawable::Pixel(Point::new(x as i32, y as i32), color)); } } // Indicate to LittlevGL that you are ready with the flushing -- 2.34.1 From 2cd2f1da87ff1356d9e31fe6b8175ffe1b8a29dd Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Sun, 19 Apr 2020 15:16:51 +0200 Subject: [PATCH 4/4] Example using lvgl mixed with embedded graphics --- examples/demo/Cargo.toml | 3 +- examples/demo/src/main.rs | 182 +++++--------------------------------- lvgl/src/display.rs | 6 +- lvgl/src/lib.rs | 1 + 4 files changed, 26 insertions(+), 166 deletions(-) diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml index 3493850..0d08288 100644 --- a/examples/demo/Cargo.toml +++ b/examples/demo/Cargo.toml @@ -10,4 +10,5 @@ publish = false [dependencies] lvgl = { path = "../../lvgl" } lvgl-sys = { path = "../../lvgl-sys" } -sdl2 = "0.33.0" +embedded-graphics = "0.6" +embedded-graphics-simulator = "0.2.0" diff --git a/examples/demo/src/main.rs b/examples/demo/src/main.rs index f06bf3a..f5b109b 100644 --- a/examples/demo/src/main.rs +++ b/examples/demo/src/main.rs @@ -1,68 +1,30 @@ use lvgl; use lvgl::Object; use lvgl_sys; -use sdl2::event::Event; -use sdl2::keyboard::Keycode; -use sdl2::pixels::Color; -use sdl2::rect::Point; -use std::mem::MaybeUninit; -use std::os::raw::c_void; -use std::panic; use std::time::Duration; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::mock_display::MockDisplay; +use embedded_graphics::prelude::*; +use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window, BinaryColorTheme, SimulatorEvent}; fn main() -> Result<(), String> { - let sdl_context = sdl2::init()?; - let video_subsystem = sdl_context.video()?; - let mut framebuffer = [[Color::from((0, 0, 0)); lvgl_sys::LV_VER_RES_MAX as usize]; - lvgl_sys::LV_HOR_RES_MAX as usize]; + let mut display: SimulatorDisplay = SimulatorDisplay::new(Size::new(lvgl_sys::LV_HOR_RES_MAX,lvgl_sys::LV_VER_RES_MAX)); - let window = video_subsystem - .window( - "TFT Display: Demo", - lvgl_sys::LV_HOR_RES_MAX, - lvgl_sys::LV_VER_RES_MAX, - ) - .position_centered() - .opengl() - .build() - .map_err(|e| e.to_string())?; - - let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; - - canvas.set_draw_color(Color::RGB(0, 0, 0)); - canvas.clear(); - canvas.present(); + let output_settings = OutputSettingsBuilder::new() + .theme(BinaryColorTheme::OledBlue) + .build(); + let mut window = Window::new("Hello World", &output_settings); unsafe { lvgl_sys::lv_init(); } - // Implement and register a function which can copy a pixel array to an area of your display: - let mut display_driver = DisplayDriver::new(move |points, colors| { - for (i, point) in points.into_iter().enumerate() { - let color = &mut framebuffer[point.x() as usize][point.y() as usize]; - *color = colors[i].clone(); - } - canvas.clear(); - for (x, line) in framebuffer.iter().enumerate() { - for (y, color) in line.iter().enumerate() { - canvas.set_draw_color(color.clone()); - canvas.draw_point(Point::new(x as i32, y as i32)).unwrap(); - } - } - canvas.present(); - }); + // Implement and register your display: + let mut display_driver = lvgl::DisplayDriver::new(&mut display); // Create screen and widgets let mut screen = display_driver.get_active_screen(); - // let mut button = lvgl::Button::new(&mut screen); - // button.set_pos(50, 50); - // button.set_size(100, 50); - // - // let mut label = lvgl::Label::new(&mut button); - // label.set_text("Hello Mundo!\0"); - let font_roboto_28 = unsafe { &lvgl_sys::lv_font_roboto_28 }; let font_noto_sans_numeric_28 = unsafe { ¬o_sans_numeric_80 }; @@ -102,22 +64,9 @@ fn main() -> Result<(), String> { power.set_label_align(lvgl::LabelAlign::Right); power.set_align(&mut screen, lvgl::Align::InTopRight, 0, 0); - let mut event_pump = sdl_context.event_pump()?; + let mut i = 0; 'running: loop { - if let Some(event) = event_pump.poll_event() { - match event { - Event::Quit { .. } - | Event::KeyDown { - keycode: Some(Keycode::Escape), - .. - } => { - break 'running; - } - _ => {} - } - } - if i > 59 { i = 0; } @@ -130,6 +79,14 @@ fn main() -> Result<(), String> { lvgl_sys::lv_task_handler(); lvgl_sys::lv_tick_inc(10); } + window.update(&display); + + for event in window.events() { + match event { + SimulatorEvent::Quit => break 'running, + _ => {} + } + } } Ok(()) @@ -139,102 +96,3 @@ fn main() -> Result<(), String> { extern "C" { pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_t; } - -#[allow(dead_code)] -struct DisplayDriver -where - F: FnMut(Vec, Vec), -{ - pub raw: lvgl_sys::lv_disp_drv_t, - callback: F, - display_buffer: MaybeUninit, - refresh_buffer: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10], -} - -impl DisplayDriver -where - F: FnMut(Vec, Vec), -{ - fn new(mut callback: F) -> Self { - // Create a display buffer for LittlevGL - let mut display_buffer = MaybeUninit::::uninit(); - let mut refresh_buffer: [MaybeUninit; - lvgl_sys::LV_HOR_RES_MAX as usize * 10] = - unsafe { MaybeUninit::uninit().assume_init() }; /*Declare a buffer for 10 lines*/ - unsafe { - // Initialize the display buffer - lvgl_sys::lv_disp_buf_init( - display_buffer.as_mut_ptr(), - refresh_buffer.as_mut_ptr() as *mut c_void, - std::ptr::null_mut(), - (lvgl_sys::LV_HOR_RES_MAX * 10) as u32, - ); - } - let mut disp_drv = unsafe { - let mut disp_drv = MaybeUninit::::uninit().assume_init(); /*Descriptor of a display driver*/ - lvgl_sys::lv_disp_drv_init(&mut disp_drv); // Basic initialization - disp_drv.flush_cb = Some(display_callback_wrapper::); // Set your driver function - disp_drv.user_data = &mut callback as *mut _ as *mut c_void; - disp_drv - }; - disp_drv.buffer = display_buffer.as_mut_ptr(); // Assign the buffer to the display - unsafe { - lvgl_sys::lv_disp_drv_register(&mut disp_drv); // Finally register the driver - } - Self { - raw: disp_drv, - callback, - display_buffer, - refresh_buffer, - } - } - - fn get_active_screen(&mut self) -> lvgl::ObjectX<'static> { - lvgl::display::get_active_screen() - } -} - -unsafe extern "C" fn display_callback_wrapper( - disp_drv: *mut lvgl_sys::lv_disp_drv_t, - area: *const lvgl_sys::lv_area_t, - color_p: *mut lvgl_sys::lv_color_t, -) where - F: FnMut(Vec, Vec), -{ - // We need to make sure panics can't escape across the FFI boundary. - let _ = panic::catch_unwind(|| { - let mut i = 0; - let disp = *disp_drv; - - // Rust code closure reference - let closure = &mut *(disp.user_data as *mut F); - - let mut points = vec![]; - let mut colors = vec![]; - - for y in (*area).y1..=(*area).y2 { - for x in (*area).x1..=(*area).x2 { - // Convert point to paint to a high-level Rust repr - points.push(Point::new(x as i32, y as i32)); - - // Convert C color representation to high-level Rust - let raw_color = *color_p.add(i); - let color = Color::from(( - raw_color.ch.red, - raw_color.ch.green, - raw_color.ch.blue, - raw_color.ch.alpha, - )); - colors.push(color); - - i = i + 1; - } - } - - // Callback the Rust closure to flush the new points to the screen - closure(points, colors); - - // Indicate to LittlevGL that you are ready with the flushing - lvgl_sys::lv_disp_flush_ready(disp_drv); - }); -} diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 7fdc0da..199be9b 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -8,11 +8,11 @@ use embedded_graphics::pixelcolor::Rgb888; use core::marker::PhantomData; -struct DisplayDriver<'a, T> +pub struct DisplayDriver<'a, T> where T: DrawTarget, { - pub raw: lvgl_sys::lv_disp_drv_t, + raw: lvgl_sys::lv_disp_drv_t, display_buffer: MaybeUninit, refresh_buffer: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10], phantom: &'a PhantomData, @@ -61,7 +61,7 @@ impl<'a, T> DisplayDriver<'a, T> where } } - fn get_active_screen(&mut self) -> ObjectX<'static> { + pub fn get_active_screen(&mut self) -> ObjectX<'static> { get_active_screen() } } diff --git a/lvgl/src/lib.rs b/lvgl/src/lib.rs index f9efaa6..aa5e592 100644 --- a/lvgl/src/lib.rs +++ b/lvgl/src/lib.rs @@ -3,4 +3,5 @@ pub mod display; mod objx; +pub use display::DisplayDriver; pub use objx::*; -- 2.34.1