Possibility to register a shared native display

This commit is contained in:
Rafael Caricio 2021-06-01 22:08:37 +02:00
parent 2326c1fbc5
commit e6d231cafa
Signed by: rafaelcaricio
GPG key ID: 3C86DBCE8E93C947
3 changed files with 75 additions and 38 deletions

View file

@ -3,6 +3,10 @@ use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window}; use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window};
use lvgl; use lvgl;
use lvgl::display::Display; use lvgl::display::Display;
use lvgl::widgets::Label;
use parking_lot::Mutex;
use std::cell::RefCell;
use std::sync::Arc;
type ColorSpace = Rgb565; type ColorSpace = Rgb565;
@ -15,7 +19,15 @@ fn main() {
let output_settings = OutputSettingsBuilder::new().scale(2).build(); let output_settings = OutputSettingsBuilder::new().scale(2).build();
let mut window = Window::new("App Example", &output_settings); let mut window = Window::new("App Example", &output_settings);
let mut shared_native_display = Arc::new(Mutex::new(embedded_graphics_display));
// LVGL usage // LVGL usage
lvgl::init(); 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();
}
} }

View file

@ -3,12 +3,17 @@ use crate::Box;
use crate::{disp_drv_register, disp_get_default, get_str_act}; use crate::{disp_drv_register, disp_get_default, get_str_act};
use crate::{Color, Obj}; use crate::{Color, Obj};
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::{ptr, result}; use core::{ptr, result};
use embedded_graphics::drawable; use embedded_graphics::drawable;
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
#[cfg(feature = "alloc")]
use parking_lot::Mutex;
#[cfg(feature = "alloc")]
use alloc::sync::Arc;
// TODO: Make this an external configuration // TODO: Make this an external configuration
const REFRESH_BUFFER_LEN: usize = 2; const REFRESH_BUFFER_LEN: usize = 2;
// Declare a buffer for the refresh rate // Declare a buffer for the refresh rate
@ -23,7 +28,9 @@ pub enum DisplayError {
type Result<T> = result::Result<T, DisplayError>; type Result<T> = result::Result<T, DisplayError>;
#[derive(Copy, Clone)] #[cfg(feature = "alloc")]
pub type SharedNativeDisplay<T> = Arc<Mutex<T>>;
pub struct Display { pub struct Display {
pub(crate) disp: NonNull<lvgl_sys::lv_disp_t>, pub(crate) disp: NonNull<lvgl_sys::lv_disp_t>,
} }
@ -33,11 +40,23 @@ impl Display {
Self { disp } Self { disp }
} }
pub fn register<C>(embedded_graphics_display: impl DrawTarget<C>) -> Result<Self> // pub fn register<T, C>(native_display: T) -> Result<Self>
// where
// T: DrawTarget<C>,
// C: PixelColor + From<Color>,
// {
// let mut display_diver = DisplayDriver::new(DisplayBuffer::new(), native_display);
// Ok(disp_drv_register(&mut display_diver)?)
// }
#[cfg(feature = "alloc")]
pub fn register_shared<T, C>(shared_native_display: &SharedNativeDisplay<T>) -> Result<Self>
where where
T: DrawTarget<C>,
C: PixelColor + From<Color>, C: PixelColor + From<Color>,
{ {
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)?) Ok(disp_drv_register(&mut display_diver)?)
} }
@ -62,37 +81,36 @@ impl DefaultDisplay {
} }
} }
#[derive(Copy, Clone)]
pub struct DisplayBuffer { pub struct DisplayBuffer {
disp_buf: lvgl_sys::lv_disp_buf_t, disp_buf: Box<lvgl_sys::lv_disp_buf_t>,
} }
impl DisplayBuffer { impl DisplayBuffer {
pub fn new() -> Self { pub fn new() -> Self {
let disp_buf = unsafe { let disp_buf = {
let mut disp_buf = MaybeUninit::uninit(); 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]); let refresh_buffer = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]);
unsafe {
lvgl_sys::lv_disp_buf_init( lvgl_sys::lv_disp_buf_init(
disp_buf.as_mut_ptr(), disp_buf.as_mut() as *mut _,
Box::into_raw(refresh_buffer) as *mut cty::c_void, Box::into_raw(refresh_buffer) as *mut cty::c_void,
ptr::null_mut(), ptr::null_mut(),
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32, lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
); );
disp_buf.assume_init() }
disp_buf
}; };
Self { disp_buf } Self { disp_buf }
} }
} }
#[derive(Copy, Clone)]
pub struct DisplayDriver<T, C> pub struct DisplayDriver<T, C>
where where
T: DrawTarget<C>, T: DrawTarget<C>,
C: PixelColor + From<Color>, C: PixelColor + From<Color>,
{ {
pub(crate) disp_drv: lvgl_sys::lv_disp_drv_t, pub(crate) disp_drv: Box<lvgl_sys::lv_disp_drv_t>,
phantom_display: PhantomData<T>, phantom_display: PhantomData<T>,
phantom_color: PhantomData<C>, phantom_color: PhantomData<C>,
} }
@ -102,25 +120,29 @@ where
T: DrawTarget<C>, T: DrawTarget<C>,
C: PixelColor + From<Color>, C: PixelColor + From<Color>,
{ {
pub fn new(display_buffer: DisplayBuffer, native_display: T) -> Self { #[cfg(feature = "alloc")]
let mut disp_drv = unsafe { pub fn new_shared(
let mut disp_drv = MaybeUninit::uninit(); display_buffer: DisplayBuffer,
lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr()); shared_native_display: SharedNativeDisplay<T>,
disp_drv.assume_init() ) -> 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). // 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(display_buffer.disp_buf) as *mut lvgl_sys::lv_disp_buf_t;
disp_drv.buffer = Box::into_raw(disp_buf) as *mut lvgl_sys::lv_disp_buf_t;
let native_display = Box::new(DisplayUserData { let native_display = Box::new(SharedDisplayUserData {
display: native_display, display: shared_native_display,
phantom: PhantomData, phantom: PhantomData,
}); });
disp_drv.user_data = disp_drv.user_data =
Box::into_raw(native_display) as *mut _ as lvgl_sys::lv_disp_drv_user_data_t; Box::into_raw(native_display) as *mut _ as lvgl_sys::lv_disp_drv_user_data_t;
disp_drv.flush_cb = Some(disp_flush_trampoline::<T, C>); // 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::<T, C>);
// We do not store any memory that can be accidentally deallocated by on the Rust side. // We do not store any memory that can be accidentally deallocated by on the Rust side.
Self { Self {
@ -131,16 +153,18 @@ where
} }
} }
pub(crate) struct DisplayUserData<T, C> #[cfg(feature = "alloc")]
pub(crate) struct SharedDisplayUserData<T, C>
where where
T: DrawTarget<C>, T: DrawTarget<C>,
C: PixelColor + From<Color>, C: PixelColor + From<Color>,
{ {
display: T, display: SharedNativeDisplay<T>,
phantom: PhantomData<C>, phantom: PhantomData<C>,
} }
unsafe extern "C" fn disp_flush_trampoline<T, C>( #[cfg(feature = "alloc")]
unsafe extern "C" fn shared_disp_flush_trampoline<T, C>(
disp_drv: *mut lvgl_sys::lv_disp_drv_t, disp_drv: *mut lvgl_sys::lv_disp_drv_t,
area: *const lvgl_sys::lv_area_t, area: *const lvgl_sys::lv_area_t,
color_p: *mut lvgl_sys::lv_color_t, color_p: *mut lvgl_sys::lv_color_t,
@ -150,7 +174,7 @@ unsafe extern "C" fn disp_flush_trampoline<T, C>(
{ {
let display_driver = *disp_drv; let display_driver = *disp_drv;
if !display_driver.user_data.is_null() { if !display_driver.user_data.is_null() {
let user_data = &mut *(display_driver.user_data as *mut DisplayUserData<T, C>); let user_data = &mut *(display_driver.user_data as *mut SharedDisplayUserData<T, C>);
let x1 = (*area).x1; let x1 = (*area).x1;
let x2 = (*area).x2; let x2 = (*area).x2;
let y1 = (*area).y1; let y1 = (*area).y1;
@ -174,7 +198,10 @@ unsafe extern "C" fn disp_flush_trampoline<T, C>(
}) })
.flatten(); .flatten();
let _ = user_data.display.draw_iter(pixels); let _ = user_data
.display
.try_lock()
.map(move |mut display| display.draw_iter(pixels));
} }
} }

View file

@ -16,9 +16,7 @@ type Result<T> = result::Result<T, CoreError>;
pub fn disp_drv_register<C: PixelColor + From<Color>, T: DrawTarget<C>>( pub fn disp_drv_register<C: PixelColor + From<Color>, T: DrawTarget<C>>(
disp_drv: &mut DisplayDriver<T, C>, disp_drv: &mut DisplayDriver<T, C>,
) -> Result<Display> { ) -> Result<Display> {
let disp_ptr = unsafe { let disp_ptr = unsafe { lvgl_sys::lv_disp_drv_register(disp_drv.disp_drv.as_mut() as *mut _) };
lvgl_sys::lv_disp_drv_register(&mut disp_drv.disp_drv as *mut lvgl_sys::lv_disp_drv_t)
};
Ok(Display::from_raw( Ok(Display::from_raw(
NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?, NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?,
)) ))