diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 5e116c8..8d2efac 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,8 +8,8 @@ publish = false [dev-dependencies] lvgl = { path = "../lvgl" } lvgl-sys = { path = "../lvgl-sys" } -embedded-graphics = "0.6" -embedded-graphics-simulator = "0.2.0" +embedded-graphics = "0.6.2" +embedded-graphics-simulator = "0.2.1" heapless = "0.5.5" cstr_core = { version = "0.2.0", features = ["alloc"] } diff --git a/examples/demo.rs b/examples/demo.rs index 60a6be5..956e4fc 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,4 +1,4 @@ -use cstr_core::{CStr, CString}; +use cstr_core::CString; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics_simulator::{ @@ -52,20 +52,6 @@ fn main() -> Result<(), LvError> { bt.set_label_align(LabelAlign::Left)?; bt.set_align(&mut screen, Align::InTopLeft, 0, 0)?; - fn set_text(text: S) -> Result<(), ()> - where - S: AsRef, - { - let _v: *const i8 = text.as_ref().as_ptr(); - Ok(()) - } - - let mut t: heapless::String = heapless::String::from("test"); - t.push('\0').unwrap(); - set_text(CStr::from_bytes_with_nul(t.as_bytes()).unwrap()).unwrap(); - set_text(cstr_core::CStr::from_bytes_with_nul("test\0".as_bytes()).unwrap()).unwrap(); - set_text(cstr_core::CString::new("test").unwrap().as_c_str()).unwrap(); - let mut power = Label::new(&mut screen)?; power.set_recolor(true)?; power.set_width(80)?; @@ -80,8 +66,8 @@ fn main() -> Result<(), LvError> { if i > 59 { i = 0; } - let val = format!("21:{:02}", i); - time.set_text(CString::new(val.as_str()).unwrap().as_c_str())?; + let val = CString::new(format!("21:{:02}", i)).unwrap(); + time.set_text(&val)?; i = 1 + i; ui.task_handler(); diff --git a/lvgl-codegen/Cargo.toml b/lvgl-codegen/Cargo.toml index de9ecfe..f38f7f9 100644 --- a/lvgl-codegen/Cargo.toml +++ b/lvgl-codegen/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/rafaelcaricio/lvgl-rs" regex = "1.4.3" quote = "1.0.9" lazy_static = "1.4.0" -proc-macro2 = "1.0.24" +proc-macro2 = "1.0.27" Inflector = "0.11.4" -syn = { version = "1.0.62", features = ["full"]} +syn = { version = "1.0.72", features = ["full"]} diff --git a/lvgl-sys/Cargo.toml b/lvgl-sys/Cargo.toml index cc7b74f..b50b140 100644 --- a/lvgl-sys/Cargo.toml +++ b/lvgl-sys/Cargo.toml @@ -20,5 +20,5 @@ name = "lvgl_sys" cty = "0.2.1" [build-dependencies] -cc = "1.0.67" -bindgen = "0.57.0" +cc = "1.0.68" +bindgen = "0.58.1" diff --git a/lvgl-sys/build.rs b/lvgl-sys/build.rs index 80ac8c2..17c4269 100644 --- a/lvgl-sys/build.rs +++ b/lvgl-sys/build.rs @@ -29,21 +29,21 @@ fn main() { }); if !conf_path.exists() { - panic!(format!( + panic!( "Directory {} referenced by {} needs to exist", conf_path.to_string_lossy(), CONFIG_NAME - )); + ); } if !conf_path.is_dir() { - panic!(format!("{} needs to be a directory", CONFIG_NAME)); + panic!("{} needs to be a directory", CONFIG_NAME); } if !conf_path.join("lv_conf.h").exists() { - panic!(format!( + panic!( "Directory {} referenced by {} needs to contain a file called lv_conf.h", conf_path.to_string_lossy(), CONFIG_NAME - )); + ); } println!( diff --git a/lvgl/src/mem.rs b/lvgl/src/mem.rs index 9167858..55ca9f6 100644 --- a/lvgl/src/mem.rs +++ b/lvgl/src/mem.rs @@ -3,11 +3,16 @@ use core::mem; use core::ops::{Deref, DerefMut}; use core::ptr::NonNull; -/// Places `T` into LVGL memory. +/// Places a sized `T` into LVGL memory. +/// +/// This is useful for cases when we need to allocate memory on Rust side +/// and handover the management of that memory to LVGL. May also be used in cases we +/// want to use dynamic memory in the Rust side. pub(crate) struct Box(NonNull); impl Box { - pub fn new(inner: T) -> LvResult> { + /// Allocate memory using LVGL memory API and place `T` in the LVGL tracked memory. + pub fn new(value: T) -> LvResult> { let size = mem::size_of::(); let inner = unsafe { let ptr = lvgl_sys::lv_mem_alloc(size as lvgl_sys::size_t) as *mut T; @@ -19,17 +24,14 @@ impl Box { "Memory address not aligned!" ); - match NonNull::new(ptr) { - Some(v) => { - // Move `T` to LVGL managed memory - // It will panic if LVGL memory is not aligned - ptr.write(inner); - Ok(v) - } - None => Err(LvError::LvOOMemory), - } + NonNull::new(ptr) + .map(|p| { + p.as_ptr().write(value); + p + }) + .ok_or(LvError::LvOOMemory)? }; - Ok(Box(inner?)) + Ok(Box(inner)) } pub fn into_raw(self) -> *mut T { @@ -69,8 +71,8 @@ impl AsMut for Box { #[cfg(test)] mod test { use super::*; - use core::mem::MaybeUninit; use std::sync::Once; + use std::vec::Vec; static INIT_LVGL: Once = Once::new(); @@ -105,6 +107,9 @@ mod test { disp: i32, } + let initial_mem_info = mem_info(); + + let mut keep = Vec::new(); for i in 0..100 { let p = Point { x: i, @@ -115,7 +120,8 @@ mod test { println!("{:?}", p); let mut b = Box::new(p).unwrap_or_else(|_| { - print_mem_info(); + let info = mem_info(); + println!("mem info: {:?}", &info); panic!("OOM"); }); @@ -123,22 +129,41 @@ mod test { let point = b.as_mut(); if point.x != i { - print_mem_info(); - println!("{:?}", point); } assert_eq!(point.x, i); + + let info = mem_info(); + println!("mem info: {:?}", &info); + keep.push(b); } + drop(keep); + + unsafe { + lvgl_sys::lv_mem_defrag(); + } + + let final_info = mem_info(); + println!("mem info: {:?}", &final_info); + + // If this fails, we are leaking memory! BOOM! \o/ + assert_eq!(initial_mem_info.free_size, final_info.free_size) } - fn print_mem_info() { - let mut info = MaybeUninit::uninit(); + fn mem_info() -> lvgl_sys::lv_mem_monitor_t { + let mut info = lvgl_sys::lv_mem_monitor_t { + total_size: 0, + free_cnt: 0, + free_size: 0, + free_biggest_size: 0, + used_cnt: 0, + max_used: 0, + used_pct: 0, + frag_pct: 0 + }; unsafe { - lvgl_sys::lv_mem_monitor(info.as_mut_ptr()); - } - if !info.as_ptr().is_null() { - let info = unsafe { info.assume_init() }; - println!("mem info: {:?}", info); + lvgl_sys::lv_mem_monitor(&mut info as *mut _); } + info } } diff --git a/lvgl/src/ui.rs b/lvgl/src/ui.rs index 699741c..4a96f90 100644 --- a/lvgl/src/ui.rs +++ b/lvgl/src/ui.rs @@ -43,7 +43,10 @@ where C: PixelColor + From, { pub fn init() -> LvResult { - if !LVGL_IN_USE.compare_and_swap(false, true, Ordering::SeqCst) { + if LVGL_IN_USE + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_ok() + { unsafe { lvgl_sys::lv_init(); }