Some additional checks on using LVGL heap memory allocator

This commit is contained in:
Rafael Caricio 2020-06-18 23:45:08 +02:00 committed by Rafael Carício
parent e70ba3a752
commit 3e7e056da6
5 changed files with 81 additions and 52 deletions

View file

@ -44,16 +44,14 @@ fn main() -> Result<(), LvError> {
button.on_event(|mut btn, event| { button.on_event(|mut btn, event| {
if let lvgl::Event::Clicked = event { if let lvgl::Event::Clicked = event {
if btn_state { if btn_state {
btn_lbl let nt = CString::new("Click me!").unwrap();
.set_text(CString::new("Click me!").unwrap().as_c_str()) btn_lbl.set_text(nt.as_c_str()).unwrap();
.unwrap();
} else { } else {
btn_lbl let nt = CString::new("Clicked!").unwrap();
.set_text(CString::new("Clicked!").unwrap().as_c_str()) btn_lbl.set_text(nt.as_c_str()).unwrap();
.unwrap();
} }
btn_state = !btn_state; btn_state = !btn_state;
println!("Clicked!"); println!("Clicked! Inner..");
btn.toggle().unwrap(); btn.toggle().unwrap();
} }
})?; })?;

View file

@ -22,11 +22,11 @@ mod tests {
unsafe { unsafe {
lv_init(); lv_init();
let horizontal_resolution = lv_disp_get_hor_res(std::ptr::null_mut()); let horizontal_resolution = lv_disp_get_hor_res(core::ptr::null_mut());
assert_eq!(horizontal_resolution, 480); assert_eq!(horizontal_resolution, 240);
let vertical_resolution = lv_disp_get_ver_res(std::ptr::null_mut()); let vertical_resolution = lv_disp_get_ver_res(core::ptr::null_mut());
assert_eq!(vertical_resolution, 320); assert_eq!(vertical_resolution, 240);
} }
} }
} }

View file

@ -1,9 +1,9 @@
#![no_std] #![cfg_attr(not(test), no_std)]
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
pub mod mem; pub(crate) mod mem;
mod support; mod support;
mod ui; mod ui;
#[macro_use] #[macro_use]

View file

@ -1,21 +1,30 @@
use crate::{LvError, LvResult}; use crate::{LvError, LvResult};
use core::mem; use core::mem;
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::ptr::NonNull; use core::ptr::NonNull;
/// Places `T` into LVGL memory. /// Places `T` into LVGL memory.
pub struct Box<T>(NonNull<T>); pub(crate) struct Box<T>(NonNull<T>);
impl<T> Box<T> { impl<T> Box<T> {
pub fn new(inner: T) -> LvResult<Box<T>> { pub fn new(inner: T) -> LvResult<Box<T>> {
let layout = mem::size_of::<T>(); assert_ne!(mem::size_of::<T>(), 0, "We don't handle ZSTs");
let size = mem::size_of::<T>();
let inner = unsafe { let inner = unsafe {
let ptr = lvgl_sys::lv_mem_alloc(layout as lvgl_sys::size_t) as *mut T; // LVGL already aligns the memory address for us
let ptr = lvgl_sys::lv_mem_alloc(size as lvgl_sys::size_t) as *mut T;
assert_eq!(
ptr as usize % mem::align_of::<T>(),
0,
"Memory address not aligned!"
);
match NonNull::new(ptr) { match NonNull::new(ptr) {
Some(v) => { Some(v) => {
// Move `T` to LVGL managed memory // Move `T` to LVGL managed memory
ptr::write(ptr, inner); // It will panic if LVGL memory is not aligned
ptr.write(inner);
Ok(v) Ok(v)
} }
None => Err(LvError::LvOOMemory), None => Err(LvError::LvOOMemory),
@ -24,8 +33,8 @@ impl<T> Box<T> {
Ok(Box(inner?)) Ok(Box(inner?))
} }
pub fn into_raw(b: Box<T>) -> *mut T { pub fn into_raw(self) -> *mut T {
let b = mem::ManuallyDrop::new(b); let b = mem::ManuallyDrop::new(self);
b.0.as_ptr() b.0.as_ptr()
} }
} }
@ -38,20 +47,6 @@ impl<T> Drop for Box<T> {
} }
} }
impl<T> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.0.as_ref() }
}
}
impl<T> DerefMut for Box<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.0.as_mut() }
}
}
impl<T> AsMut<T> for Box<T> { impl<T> AsMut<T> for Box<T> {
fn as_mut(&mut self) -> &mut T { fn as_mut(&mut self) -> &mut T {
unsafe { self.0.as_mut() } unsafe { self.0.as_mut() }
@ -61,12 +56,23 @@ impl<T> AsMut<T> for Box<T> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use core::mem::MaybeUninit;
use std::sync::Once;
static INIT_LVGL: Once = Once::new();
fn init() {
INIT_LVGL.call_once(|| {
unsafe {
lvgl_sys::lv_init();
};
});
}
#[test] #[test]
fn place_value_in_lv_mem() { fn place_value_in_lv_mem() {
unsafe { init();
lvgl_sys::_lv_mem_init();
};
let v = Box::new(5).unwrap(); let v = Box::new(5).unwrap();
drop(v); drop(v);
let v = Box::new(10).unwrap(); let v = Box::new(10).unwrap();
@ -75,26 +81,51 @@ mod test {
#[test] #[test]
fn place_complex_value_in_lv_mem() { fn place_complex_value_in_lv_mem() {
unsafe { init();
lvgl_sys::_lv_mem_init();
};
#[repr(C)]
#[derive(Debug)]
struct Point { struct Point {
x: u64, x: u64,
y: u64, y: i8,
t: i32,
disp: i32, disp: i32,
} }
let p = Point { for i in 0..100 {
x: 32, let p = Point {
y: 240, x: i,
disp: -100, y: 42,
}; t: 0,
disp: -100,
};
let b = Box::new(p).unwrap(); println!("{:?}", p);
let mut b = Box::new(p).unwrap_or_else(|_| {
print_mem_info();
panic!("OOM");
});
assert_eq!(b.x, 32); println!("memory address is {:p}", b.as_mut());
assert_eq!(b.y, 240);
assert_eq!(b.disp, -100); let point = b.as_mut();
if point.x != i {
print_mem_info();
println!("{:?}", point);
}
assert_eq!(point.x, i);
}
}
fn print_mem_info() {
let mut info = MaybeUninit::uninit();
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);
}
} }
} }

View file

@ -16,7 +16,7 @@ static LVGL_IN_USE: AtomicBool = AtomicBool::new(false);
// 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
const BUF_SIZE: usize = lvgl_sys::LV_HOR_RES_MAX as usize * REFRESH_BUFFER_LEN; pub(crate) const BUF_SIZE: usize = lvgl_sys::LV_HOR_RES_MAX as usize * REFRESH_BUFFER_LEN;
pub struct UI<T, C> pub struct UI<T, C>
where where