Some additional checks on using LVGL heap memory allocator
This commit is contained in:
parent
e70ba3a752
commit
3e7e056da6
5 changed files with 81 additions and 52 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
101
lvgl/src/mem.rs
101
lvgl/src/mem.rs
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i in 0..100 {
|
||||||
let p = Point {
|
let p = Point {
|
||||||
x: 32,
|
x: i,
|
||||||
y: 240,
|
y: 42,
|
||||||
|
t: 0,
|
||||||
disp: -100,
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue