From a7bef1cd54a9294767027e9e96d625c73f55dcfa Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Thu, 28 May 2020 22:12:29 +0200 Subject: [PATCH] New API test using std/alloc objects --- lvgl/src/api.rs | 207 ++++++++++++++++++++++++++++++++++++++++++++++++ lvgl/src/lib.rs | 6 +- 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 lvgl/src/api.rs diff --git a/lvgl/src/api.rs b/lvgl/src/api.rs new file mode 100644 index 0000000..dce81ef --- /dev/null +++ b/lvgl/src/api.rs @@ -0,0 +1,207 @@ +use core::marker::PhantomData; +use core::time::Duration; +use core::sync::atomic::{AtomicBool, Ordering}; + +// There can only be a single reference to LittlevGL library. +static LVGL_IN_USE: AtomicBool = AtomicBool::new(false); + +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum LvError { + AlreadyInUse, +} + +pub struct UI { + // LittlevGL is not thread-safe by default. + _not_send: PhantomData<*const ()> +} + +impl UI { + pub fn init() -> Result { + if LVGL_IN_USE.compare_and_swap(false, true, Ordering::SeqCst) == false { + // lvgl_sys::lv_init(); + Ok(Self { + _not_send: PhantomData, + }) + } else { + Err(LvError::AlreadyInUse) + } + } + + pub fn disp_drv_register(&mut self, _display: &mut DisplayDriver) { + // register it + // lvgl_sys::lv_disp_drv_register(&mut disp_drv); + } + + pub fn tick_inc(&mut self, _tick_period: Duration) { + // lvgl_sys::lv_tick_inc(tick_period); + } + + pub fn task_handler(&mut self) { + // lvgl_sys::lv_task_handler(); + } +} + +pub struct DisplayDriver { + refresh_lines: u32, + current_screen: Screen, +} + +impl DisplayDriver { + pub fn new(refresh_lines: u32) -> Self { + Self{ refresh_lines, current_screen: Screen::new() } + } + + // Ensure cannot delete the current loaded screen + pub fn load_scr(&mut self, screen: Screen) { + self.current_screen = screen; + } + + pub fn scr_act(&mut self) -> &mut Screen { + &mut self.current_screen + } +} + +pub trait LvObject { + fn label_create(&self) -> Label where Self: Sized { + Label{ parent: self } + } + + fn btn_create(&self) -> Button where Self: Sized, F: FnMut() { + Button{ parent: self, event_callback: None } + } +} + +pub struct Screen { + _not_send: PhantomData<*const ()> +} + +impl Screen { + pub fn new() -> Self { + Self { _not_send: PhantomData } + } +} + +impl LvObject for Screen {} + +pub struct Label<'a> { + parent: &'a dyn LvObject, +} + +impl<'a> Label<'a> { + pub fn set_text(&mut self, _text: &str) { + // set text call to unsafe... + } +} + +impl<'a> LvObject for Label<'a> {} + +pub struct Button<'a, F> where F: FnMut() { + parent: &'a dyn LvObject, + event_callback: Option, +} + +impl<'a, F> Button<'a, F> where F: FnMut() { + pub fn on_event(&mut self, callback: F) { + // add callback + self.event_callback = Some(callback); + } +} + +impl<'a, F> LvObject for Button<'a, F> where F: FnMut() {} + + +#[cfg(test)] +mod test { + use crate::api::{UI, DisplayDriver, LvObject}; + use core::time::Duration; + use std::sync::{Mutex, Arc}; + + #[test] + fn basic_usage() { + let mut ui = UI::init().unwrap(); + + let refresh_lines = 10; + let mut display = DisplayDriver::new(refresh_lines); + ui.disp_drv_register(&mut display); + let display = Arc::new(Mutex::new(display)); + + { + let mut disp = display.clone(); + let mut d = disp.lock().unwrap(); + let screen = d.scr_act(); + + let mut button = screen.btn_create(); + + let mut inner_disp = display.clone(); + button.on_event(|| { + // something + let mut disp = inner_disp.lock().unwrap(); + let screen = disp.scr_act(); + let mut label = screen.label_create(); + label.set_text("Clicked"); + }); + + let mut label = button.label_create(); + label.set_text("Click me!"); + }; + + { + let mut disp = display.clone(); + let mut d = disp.lock().unwrap(); + let screen = d.scr_act(); + let mut button2 = screen.btn_create(); + button2.on_event(|| { + // else + }); + let mut label2 = button2.label_create(); + label2.set_text("Else"); + }; + + ui.tick_inc(Duration::from_millis(5)); + ui.task_handler(); + } + + #[test] + fn test_usage() { + // // can use Arc> to share between threads + // let mut app = lvgl::App::init().unwrap(); + // + // let disp = DisplayDriver::new(); + // app.register_display_driver(&disp); // takes (&mut self, ...) + // + // let screen: &mut lvgl::Screen = disp.new_screen(); // takes (&mut self) + // disp.load_screen(&screen); // takes (&self) because it just need the ref to + // // the screen to load, as all the screens are already internal. + // + // let button = screen.new_button(); // takes (&self) + // button.on_event(|&mut app, &mut btn, ev| { + // let mut label: &mut Label = app.cur_screen().new_label(); + // if let lvgl::Event::Clicked = ev { + // btn.set_text("clicked!"); + // } + // app.load_screen(&screen); + // }); + // + // let mut lbl_click = button.new_label(); + // lbl_click.set_text("Click me!"); + // + // + // // lvgl::Timer returns reference to same internal object + // app.tick(Duration::from_millis(1)); // takes (&mut self) + // + // app.task_handler(); // takes (&mut self) + // + // // Multiple Displays can be instantiated + // // Multiple Screen's in each Display + // // Screen can be instantiated independently + // // Any specific object impl Screenable(trait) (can be used anywhere Screen is used) + // // To get active screen from a Display use `lv_disp_get_scr_act(disp)` + // let screen = disp.get_active_screen(); + // // To set an active screen in a Display use `lv_disp_load_scr(disp, scr)` + // disp.load_screen(screen); + // + // let mut screen = Screen::new(); + // let mut button = screen.add_button(); + // let mut btn_lbl = button.create_label(); + } +} diff --git a/lvgl/src/lib.rs b/lvgl/src/lib.rs index aa5e592..e5956ca 100644 --- a/lvgl/src/lib.rs +++ b/lvgl/src/lib.rs @@ -1,7 +1,11 @@ -#![no_std] +// #![no_std] pub mod display; mod objx; +mod api; + pub use display::DisplayDriver; pub use objx::*; + +