From e6d231cafa33940ebd019fa1d260cece79ede77e Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Tue, 1 Jun 2021 22:08:37 +0200 Subject: [PATCH] Possibility to register a shared native display --- examples/app.rs | 14 ++++++- lvgl/src/display.rs | 95 +++++++++++++++++++++++++++---------------- lvgl/src/functions.rs | 4 +- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/examples/app.rs b/examples/app.rs index 77f8f2d..7aa75ed 100644 --- a/examples/app.rs +++ b/examples/app.rs @@ -3,6 +3,10 @@ use embedded_graphics::prelude::*; use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window}; use lvgl; use lvgl::display::Display; +use lvgl::widgets::Label; +use parking_lot::Mutex; +use std::cell::RefCell; +use std::sync::Arc; type ColorSpace = Rgb565; @@ -15,7 +19,15 @@ fn main() { let output_settings = OutputSettingsBuilder::new().scale(2).build(); let mut window = Window::new("App Example", &output_settings); + let mut shared_native_display = Arc::new(Mutex::new(embedded_graphics_display)); + // LVGL usage lvgl::init(); - Display::register(embedded_graphics_display).unwrap(); + let display = Display::register_shared(&shared_native_display).unwrap(); + let label = Label::new().unwrap(); + + { + let mut val = shared_native_display.lock(); + val.draw_pixel(Pixel::default()).unwrap(); + } } diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 88898d0..a864993 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -3,12 +3,17 @@ use crate::Box; use crate::{disp_drv_register, disp_get_default, get_str_act}; use crate::{Color, Obj}; use core::marker::PhantomData; -use core::mem::MaybeUninit; use core::ptr::NonNull; use core::{ptr, result}; use embedded_graphics::drawable; use embedded_graphics::prelude::*; +#[cfg(feature = "alloc")] +use parking_lot::Mutex; + +#[cfg(feature = "alloc")] +use alloc::sync::Arc; + // TODO: Make this an external configuration const REFRESH_BUFFER_LEN: usize = 2; // Declare a buffer for the refresh rate @@ -23,7 +28,9 @@ pub enum DisplayError { type Result = result::Result; -#[derive(Copy, Clone)] +#[cfg(feature = "alloc")] +pub type SharedNativeDisplay = Arc>; + pub struct Display { pub(crate) disp: NonNull, } @@ -33,11 +40,23 @@ impl Display { Self { disp } } - pub fn register(embedded_graphics_display: impl DrawTarget) -> Result + // pub fn register(native_display: T) -> Result + // where + // T: DrawTarget, + // C: PixelColor + From, + // { + // let mut display_diver = DisplayDriver::new(DisplayBuffer::new(), native_display); + // Ok(disp_drv_register(&mut display_diver)?) + // } + + #[cfg(feature = "alloc")] + pub fn register_shared(shared_native_display: &SharedNativeDisplay) -> Result where + T: DrawTarget, C: PixelColor + From, { - let mut display_diver = DisplayDriver::new(DisplayBuffer::new(), embedded_graphics_display); + let mut display_diver = + DisplayDriver::new_shared(DisplayBuffer::new(), Arc::clone(shared_native_display)); Ok(disp_drv_register(&mut display_diver)?) } @@ -62,37 +81,36 @@ impl DefaultDisplay { } } -#[derive(Copy, Clone)] pub struct DisplayBuffer { - disp_buf: lvgl_sys::lv_disp_buf_t, + disp_buf: Box, } impl DisplayBuffer { pub fn new() -> Self { - let disp_buf = unsafe { - let mut disp_buf = MaybeUninit::uninit(); + let disp_buf = { + let mut disp_buf = Box::new(lvgl_sys::lv_disp_buf_t::default()); let refresh_buffer = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]); - - lvgl_sys::lv_disp_buf_init( - disp_buf.as_mut_ptr(), - Box::into_raw(refresh_buffer) as *mut cty::c_void, - ptr::null_mut(), - lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32, - ); - disp_buf.assume_init() + unsafe { + lvgl_sys::lv_disp_buf_init( + disp_buf.as_mut() as *mut _, + Box::into_raw(refresh_buffer) as *mut cty::c_void, + ptr::null_mut(), + lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32, + ); + } + disp_buf }; Self { disp_buf } } } -#[derive(Copy, Clone)] pub struct DisplayDriver where T: DrawTarget, C: PixelColor + From, { - pub(crate) disp_drv: lvgl_sys::lv_disp_drv_t, + pub(crate) disp_drv: Box, phantom_display: PhantomData, phantom_color: PhantomData, } @@ -102,25 +120,29 @@ where T: DrawTarget, C: PixelColor + From, { - pub fn new(display_buffer: DisplayBuffer, native_display: T) -> Self { - let mut disp_drv = unsafe { - let mut disp_drv = MaybeUninit::uninit(); - lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr()); - disp_drv.assume_init() - }; + #[cfg(feature = "alloc")] + pub fn new_shared( + display_buffer: DisplayBuffer, + shared_native_display: SharedNativeDisplay, + ) -> Self { + let mut disp_drv = Box::new(lvgl_sys::lv_disp_drv_t::default()); + unsafe { + lvgl_sys::lv_disp_drv_init(disp_drv.as_mut() as *mut _); + } // We need to add to a `Box`, so it's copied to a memory location in the "heap" (LVGL statically allocated heap). - let disp_buf = Box::new(display_buffer.disp_buf); - disp_drv.buffer = Box::into_raw(disp_buf) as *mut lvgl_sys::lv_disp_buf_t; + disp_drv.buffer = Box::into_raw(display_buffer.disp_buf) as *mut lvgl_sys::lv_disp_buf_t; - let native_display = Box::new(DisplayUserData { - display: native_display, + let native_display = Box::new(SharedDisplayUserData { + display: shared_native_display, phantom: PhantomData, }); disp_drv.user_data = Box::into_raw(native_display) as *mut _ as lvgl_sys::lv_disp_drv_user_data_t; - disp_drv.flush_cb = Some(disp_flush_trampoline::); + // Sets trampoline pointer to the function implementation using the types (T, C) that + // are used in this instance of `DisplayDriver`. + disp_drv.flush_cb = Some(shared_disp_flush_trampoline::); // We do not store any memory that can be accidentally deallocated by on the Rust side. Self { @@ -131,16 +153,18 @@ where } } -pub(crate) struct DisplayUserData +#[cfg(feature = "alloc")] +pub(crate) struct SharedDisplayUserData where T: DrawTarget, C: PixelColor + From, { - display: T, + display: SharedNativeDisplay, phantom: PhantomData, } -unsafe extern "C" fn disp_flush_trampoline( +#[cfg(feature = "alloc")] +unsafe extern "C" fn shared_disp_flush_trampoline( disp_drv: *mut lvgl_sys::lv_disp_drv_t, area: *const lvgl_sys::lv_area_t, color_p: *mut lvgl_sys::lv_color_t, @@ -150,7 +174,7 @@ unsafe extern "C" fn disp_flush_trampoline( { let display_driver = *disp_drv; if !display_driver.user_data.is_null() { - let user_data = &mut *(display_driver.user_data as *mut DisplayUserData); + let user_data = &mut *(display_driver.user_data as *mut SharedDisplayUserData); let x1 = (*area).x1; let x2 = (*area).x2; let y1 = (*area).y1; @@ -174,7 +198,10 @@ unsafe extern "C" fn disp_flush_trampoline( }) .flatten(); - let _ = user_data.display.draw_iter(pixels); + let _ = user_data + .display + .try_lock() + .map(move |mut display| display.draw_iter(pixels)); } } diff --git a/lvgl/src/functions.rs b/lvgl/src/functions.rs index d62adef..2490130 100644 --- a/lvgl/src/functions.rs +++ b/lvgl/src/functions.rs @@ -16,9 +16,7 @@ type Result = result::Result; pub fn disp_drv_register, T: DrawTarget>( disp_drv: &mut DisplayDriver, ) -> Result { - let disp_ptr = unsafe { - lvgl_sys::lv_disp_drv_register(&mut disp_drv.disp_drv as *mut lvgl_sys::lv_disp_drv_t) - }; + let disp_ptr = unsafe { lvgl_sys::lv_disp_drv_register(disp_drv.disp_drv.as_mut() as *mut _) }; Ok(Display::from_raw( NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?, ))