diff --git a/examples/demo.rs b/examples/demo.rs index 91d2d65..fe35e77 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -5,10 +5,9 @@ use embedded_graphics_simulator::{ OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window, }; use lvgl; -use lvgl::display::{DefaultDisplay, Display, DrawBuffer}; use lvgl::style::Style; use lvgl::widgets::{Label, LabelAlign}; -use lvgl::{Align, Color, LvError, Part, State, Widget, UI}; +use lvgl::{Align, Color, DefaultDisplay, Display, DrawBuffer, LvError, Part, State, Widget}; use lvgl_sys; use parking_lot::Mutex; use std::sync::Arc as SyncArc; @@ -16,25 +15,32 @@ use std::thread; use std::thread::sleep; use std::time::{Duration, Instant}; -static DRAW_BUFFER: DrawBuffer = DrawBuffer::new(); - fn main() -> Result<(), LvError> { - lvgl::init(); - let embedded_graphics_display: SimulatorDisplay = SimulatorDisplay::new(Size::new( - lvgl_sys::LV_HOR_RES_MAX, - lvgl_sys::LV_VER_RES_MAX, + lvgl::DISP_HOR_RES as u32, + lvgl::DISP_VER_RES as u32, )); let output_settings = OutputSettingsBuilder::new().scale(1).build(); let mut window = Window::new("PineTime", &output_settings); - // Implement and register your display: let shared_native_display = SyncArc::new(Mutex::new(embedded_graphics_display)); - let _display = Display::register_shared(&DRAW_BUFFER, &shared_native_display)?; + + // LVGL-rs usage starts here + lvgl::init(); + + // LVGL will render the graphics here first, and seed the rendered image to the + // display. The buffer size can be set freely but 1/10 screen size is a good starting point. + const REFRESH_BUFFER_SIZE: usize = lvgl::DISP_HOR_RES * lvgl::DISP_VER_RES / 10; + static DRAW_BUFFER: DrawBuffer = DrawBuffer::new(); + + // Register your native display with LVGL. We use the `Display::register_shared()` method here, + // but that's because the Simulator needs a mutable reference to the display so it can draw + // updates. On your embedded device code, you will use `Display::register()`. + let display = Display::register_shared(&DRAW_BUFFER, &shared_native_display)?; // Create screen and widgets - let mut screen = DefaultDisplay::get_scr_act()?; + let mut screen = display.get_scr_act()?; println!("Before all widgets: {:?}", mem_info()); diff --git a/examples/include/lv_conf.h b/examples/include/lv_conf.h index 477f044..cc5f026 100644 --- a/examples/include/lv_conf.h +++ b/examples/include/lv_conf.h @@ -80,7 +80,7 @@ typedef int16_t lv_coord_t; #define LV_MEM_CUSTOM 0 #if LV_MEM_CUSTOM == 0 /* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ -# define LV_MEM_SIZE (1048576U) // 1Mb +# define LV_MEM_SIZE (14U * 1024U) /* Compiler prefix for a big array declaration */ # define LV_MEM_ATTR diff --git a/lvgl/Cargo.toml b/lvgl/Cargo.toml index 4083b3d..737b665 100644 --- a/lvgl/Cargo.toml +++ b/lvgl/Cargo.toml @@ -18,7 +18,6 @@ embedded-graphics = "0.6.2" cstr_core = "0.2.3" bitflags = "1.2.1" parking_lot = "0.11.1" -lazy_static = "1.4.0" heapless = "0.7.1" [features] diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 5e77e2c..aa54759 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -1,12 +1,11 @@ use crate::functions::CoreError; -use crate::Box; use crate::{disp_drv_register, disp_get_default, get_str_act}; +use crate::{Box, RunOnce}; use crate::{Color, Obj}; -use core::cell::{Cell, RefCell}; +use core::cell::RefCell; use core::marker::PhantomData; use core::mem::MaybeUninit; use core::ptr::NonNull; -use core::sync::atomic::{AtomicBool, Ordering}; use core::{ptr, result}; use embedded_graphics::drawable; use embedded_graphics::prelude::*; @@ -16,10 +15,8 @@ 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 -const BUF_SIZE: usize = lvgl_sys::LV_HOR_RES_MAX as usize * REFRESH_BUFFER_LEN; +pub const DISP_HOR_RES: usize = lvgl_sys::LV_HOR_RES_MAX as usize; +pub const DISP_VER_RES: usize = lvgl_sys::LV_VER_RES_MAX as usize; #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum DisplayError { @@ -42,7 +39,10 @@ impl Display { Self { disp } } - pub fn register(draw_buffer: &'static DrawBuffer, native_display: T) -> Result + pub fn register( + draw_buffer: &'static DrawBuffer, + native_display: T, + ) -> Result where T: DrawTarget, C: PixelColor + From, @@ -52,8 +52,8 @@ impl Display { } #[cfg(feature = "alloc")] - pub fn register_shared( - draw_buffer: &'static DrawBuffer, + pub fn register_shared( + draw_buffer: &'static DrawBuffer, shared_native_display: &SharedNativeDisplay, ) -> Result where @@ -65,7 +65,7 @@ impl Display { Ok(disp_drv_register(&mut display_diver)?) } - pub fn get_str_act(&self) -> Result { + pub fn get_scr_act(&self) -> Result { Ok(get_str_act(Some(&self))?) } } @@ -86,33 +86,29 @@ impl DefaultDisplay { } } -pub struct DrawBuffer { - initialized: AtomicBool, - refresh_buffer: Mutex>>, +pub struct DrawBuffer { + initialized: RunOnce, + refresh_buffer: Mutex>>, } -impl DrawBuffer { +impl DrawBuffer { pub const fn new() -> Self { Self { - initialized: AtomicBool::new(false), + initialized: RunOnce::new(), refresh_buffer: const_mutex(RefCell::new(heapless::Vec::new())), } } fn get_ptr(&self) -> Option> { - if self - .initialized - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { + if self.initialized.swap_and_check() { let mut inner: MaybeUninit = MaybeUninit::uninit(); - let refresh_buffer_guard = self.refresh_buffer.lock(); + let primary_buffer_guard = self.refresh_buffer.lock(); let draw_buf = unsafe { lvgl_sys::lv_disp_buf_init( inner.as_mut_ptr(), - refresh_buffer_guard.borrow_mut().as_mut_ptr() as *mut _ as *mut cty::c_void, + primary_buffer_guard.borrow_mut().as_mut_ptr() as *mut _ as *mut cty::c_void, ptr::null_mut(), - lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32, + N as u32, ); inner.assume_init() }; @@ -138,7 +134,10 @@ where T: DrawTarget, C: PixelColor + From, { - pub fn new(draw_buffer: &'static DrawBuffer, native_display: T) -> Result { + pub fn new( + draw_buffer: &'static DrawBuffer, + native_display: T, + ) -> Result { let mut disp_drv = unsafe { let mut inner = MaybeUninit::uninit(); lvgl_sys::lv_disp_drv_init(inner.as_mut_ptr()); @@ -171,8 +170,8 @@ where } #[cfg(feature = "alloc")] - pub fn new_shared( - draw_buffer: &'static DrawBuffer, + pub fn new_shared( + draw_buffer: &'static DrawBuffer, shared_native_display: SharedNativeDisplay, ) -> Result { let mut disp_drv = unsafe { @@ -339,7 +338,7 @@ mod tests { let display = Display::default(); let _screen_direct = display - .get_str_act() + .get_scr_act() .expect("Return screen directly from the display instance"); let _screen_default = @@ -352,7 +351,7 @@ mod tests { let display = Display::default(); let _screen = display - .get_str_act() + .get_scr_act() .expect("Return screen directly from the display instance"); Ok(()) diff --git a/lvgl/src/lib.rs b/lvgl/src/lib.rs index b3beb71..779f20b 100644 --- a/lvgl/src/lib.rs +++ b/lvgl/src/lib.rs @@ -17,9 +17,6 @@ #[macro_use] extern crate bitflags; -#[macro_use] -extern crate lazy_static; - #[macro_use] mod lv_core; @@ -47,7 +44,8 @@ pub(crate) mod mem; #[cfg(not(feature = "lvgl_alloc"))] use crate::mem::Box; -pub mod display; +mod display; +pub use display::*; mod functions; mod support; mod ui; @@ -65,7 +63,7 @@ impl RunOnce { Self(AtomicBool::new(false)) } - fn swap_and_get(&self) -> bool { + fn swap_and_check(&self) -> bool { self.0 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) .is_ok() @@ -75,7 +73,7 @@ impl RunOnce { static LVGL_INITIALIZED: RunOnce = RunOnce::new(); pub fn init() { - if LVGL_INITIALIZED.swap_and_get() { + if LVGL_INITIALIZED.swap_and_check() { unsafe { lvgl_sys::lv_init(); } @@ -92,11 +90,13 @@ pub(crate) mod tests { pub(crate) fn initialize_test() { init(); - static DRAW_BUFFER: DrawBuffer = DrawBuffer::new(); + let embedded_graphics_display: MockDisplay = Default::default(); + + const REFRESH_BUFFER_SIZE: usize = 64 * 64 / 10; + static DRAW_BUFFER: DrawBuffer = DrawBuffer::new(); static ONCE_INIT: RunOnce = RunOnce::new(); - if ONCE_INIT.swap_and_get() { - let embedded_graphics_display: MockDisplay = Default::default(); + if ONCE_INIT.swap_and_check() { let _ = Display::register(&DRAW_BUFFER, embedded_graphics_display).unwrap(); } }