Let users deal with Errors

This commit is contained in:
Rafael Caricio 2020-06-07 20:29:35 +02:00 committed by Rafael Carício
parent 80d976ac1f
commit 36bae837f8
11 changed files with 132 additions and 108 deletions

View file

@ -5,14 +5,14 @@ use embedded_graphics_simulator::{
};
use lvgl::style::Style;
use lvgl::widgets::{Arc, ArcPart, Label, LabelAlign};
use lvgl::Widget;
use lvgl::{self, Align, Color, DisplayDriver, Event, Part, State, UI};
use lvgl::{self, Align, Color, DisplayDriver, Part, State, UI};
use lvgl::{LvError, Widget};
use lvgl_sys;
use std::sync::{mpsc, Arc as StdArc, Mutex};
use std::thread::sleep;
use std::time::Duration;
fn main() -> Result<(), String> {
fn main() -> Result<(), LvError> {
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
@ -21,35 +21,35 @@ fn main() -> Result<(), String> {
let output_settings = OutputSettingsBuilder::new().scale(2).build();
let mut window = Window::new("Arc Example", &output_settings);
let mut ui = UI::init().unwrap();
let mut ui = UI::init()?;
// Implement and register your display:
let display_driver = DisplayDriver::new(&mut display);
ui.disp_drv_register(display_driver);
// Create screen and widgets
let mut screen = ui.scr_act();
let mut screen = ui.scr_act()?;
let mut screen_style = Style::default();
screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
screen_style.set_radius(State::DEFAULT, 0);
screen.add_style(Part::Main, screen_style);
screen.add_style(Part::Main, screen_style)?;
// Create the arc object
let mut arc = Arc::new(&mut screen);
arc.set_size(150, 150);
arc.set_align(&mut screen, Align::Center, 0, 10);
arc.set_start_angle(135, ArcPart::Indicator);
arc.set_end_angle(135, ArcPart::Indicator);
let mut arc = Arc::new(&mut screen)?;
arc.set_size(150, 150)?;
arc.set_align(&mut screen, Align::Center, 0, 10)?;
arc.set_start_angle(135, ArcPart::Indicator)?;
arc.set_end_angle(135, ArcPart::Indicator)?;
let mut loading_lbl = Label::new(&mut screen);
loading_lbl.set_text("Loading...");
loading_lbl.set_align(&mut arc, Align::OutTopMid, 0, -10);
loading_lbl.set_label_align(LabelAlign::Center);
let mut loading_lbl = Label::new(&mut screen)?;
loading_lbl.set_text("Loading...")?;
loading_lbl.set_align(&mut arc, Align::OutTopMid, 0, -10)?;
loading_lbl.set_label_align(LabelAlign::Center)?;
let mut loading_style = Style::default();
loading_style.set_text_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
loading_lbl.add_style(Part::Main, loading_style);
loading_lbl.add_style(Part::Main, loading_style)?;
let threaded_ui = StdArc::new(Mutex::new(ui));
@ -73,13 +73,9 @@ fn main() -> Result<(), String> {
if i > 270 {
forward = if forward { false } else { true };
i = 1;
threaded_ui
.lock()
.unwrap()
.event_send(&mut loading_lbl, Event::Clicked)
}
angle = if forward { angle + 1 } else { angle - 1 };
arc.set_end_angle(angle + 135, ArcPart::Indicator);
arc.set_end_angle(angle + 135, ArcPart::Indicator)?;
i += 1;
sleep(Duration::from_millis(10));

View file

@ -20,6 +20,7 @@ impl DisplayDriver {
let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
// Declare a buffer for the refresh rate
// TODO: Make this an external configuration
const REFRESH_BUFFER_LEN: usize = 2;
let refresh_buffer1 = Box::new(
MaybeUninit::<
@ -94,13 +95,15 @@ unsafe extern "C" fn display_callback_wrapper<T, C>(
// have an standard unwinding mechanism to rely upon.
let display_driver = *disp_drv;
// Rust code closure reference
let device = &mut *(display_driver.user_data as *mut T);
let x1 = (*area).x1;
let x2 = (*area).x2;
let y1 = (*area).y1;
let y2 = (*area).y2;
// TODO: Can we do anything when there is a error while flushing?
let _ = display_flush(device, (x1, x2), (y1, y2), color_p);
if !display_driver.user_data.is_null() {
let device = &mut *(display_driver.user_data as *mut T);
let x1 = (*area).x1;
let x2 = (*area).x2;
let y1 = (*area).y1;
let y2 = (*area).y2;
// TODO: Can we do anything when there is a error while flushing?
let _ = display_flush(device, (x1, x2), (y1, y2), color_p);
}
// Indicate to LittlevGL that we are ready with the flushing
lvgl_sys::lv_disp_flush_ready(disp_drv);
}
@ -136,6 +139,5 @@ where
})
.flatten();
// TODO: Maybe find a way to use `draw_image` method on the device instance.
Ok(display.draw_iter(pixels)?)
}

View file

@ -1,4 +1,4 @@
use crate::{DisplayDriver, Event, Obj, Widget};
use crate::{DisplayDriver, Event, LvError, LvResult, Obj, Widget};
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::ptr;
@ -9,12 +9,6 @@ use core::time::Duration;
// 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 {
Uninitialized,
AlreadyInUse,
}
pub struct UI {
// LittlevGL is not thread-safe by default.
_not_sync: PhantomData<*mut ()>,
@ -24,7 +18,7 @@ pub struct UI {
unsafe impl Send for UI {}
impl UI {
pub fn init() -> Result<Self, LvError> {
pub fn init() -> LvResult<Self> {
if !LVGL_IN_USE.compare_and_swap(false, true, Ordering::SeqCst) {
unsafe {
lvgl_sys::lv_init();
@ -47,20 +41,21 @@ impl UI {
}
}
pub fn scr_act(&self) -> Obj {
pub fn scr_act(&self) -> LvResult<Obj> {
unsafe {
let screen = lvgl_sys::lv_disp_get_scr_act(ptr::null_mut());
Obj::from_raw(NonNull::new_unchecked(screen))
Ok(Obj::from_raw(NonNull::new(screen)?))
}
}
pub fn event_send<T>(&mut self, obj: &mut T, event: Event<T::SpecialEvent>)
pub fn event_send<T>(&mut self, obj: &mut T, event: Event<T::SpecialEvent>) -> LvResult<()>
where
T: Widget,
{
unsafe {
lvgl_sys::lv_event_send(obj.raw().as_mut(), event.into(), ptr::null_mut());
lvgl_sys::lv_event_send(obj.raw()?.as_mut(), event.into(), ptr::null_mut());
}
Ok(())
}
pub fn tick_inc(&mut self, tick_period: Duration) {

View file

@ -1,3 +1,4 @@
#![feature(try_trait)]
#![no_std]
extern crate alloc;
@ -12,6 +13,6 @@ mod lv_core;
pub mod widgets;
pub use display::DisplayDriver;
pub use global::{LvError, UI};
pub use global::UI;
pub use lv_core::*;
pub use support::*;

View file

@ -1,14 +1,12 @@
use crate::lv_core::style::Style;
use crate::Align;
use crate::{Align, LvError, LvResult};
use alloc::boxed::Box;
use core::ptr;
const PANIC_MESSAGE: &str = "Value was dropped by LittlevGL";
/// Represents a native LittlevGL object
pub trait NativeObject {
/// Provide common way to access to the underlying native object pointer.
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>;
fn raw(&self) -> LvResult<ptr::NonNull<lvgl_sys::lv_obj_t>>;
}
/// Generic LVGL object.
@ -21,8 +19,12 @@ pub struct Obj {
}
impl NativeObject for Obj {
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t> {
ptr::NonNull::new(self.raw).expect(PANIC_MESSAGE)
fn raw(&self) -> LvResult<ptr::NonNull<lvgl_sys::lv_obj_t>> {
if let Some(non_null_ptr) = ptr::NonNull::new(self.raw) {
Ok(non_null_ptr)
} else {
Err(LvError::InvalidReference)
}
}
}
@ -38,57 +40,63 @@ pub trait Widget: NativeObject {
///
unsafe fn from_raw(raw_pointer: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self;
fn add_style(&mut self, part: Self::Part, style: Style) {
fn add_style(&mut self, part: Self::Part, style: Style) -> LvResult<()> {
unsafe {
lvgl_sys::lv_obj_add_style(self.raw().as_mut(), part.into(), Box::into_raw(style.raw));
lvgl_sys::lv_obj_add_style(self.raw()?.as_mut(), part.into(), Box::into_raw(style.raw));
};
Ok(())
}
fn set_pos(&mut self, x: i16, y: i16) {
fn set_pos(&mut self, x: i16, y: i16) -> LvResult<()> {
unsafe {
lvgl_sys::lv_obj_set_pos(
self.raw().as_mut(),
self.raw()?.as_mut(),
x as lvgl_sys::lv_coord_t,
y as lvgl_sys::lv_coord_t,
);
}
Ok(())
}
fn set_size(&mut self, w: i16, h: i16) {
fn set_size(&mut self, w: i16, h: i16) -> LvResult<()> {
unsafe {
lvgl_sys::lv_obj_set_size(
self.raw().as_mut(),
self.raw()?.as_mut(),
w as lvgl_sys::lv_coord_t,
h as lvgl_sys::lv_coord_t,
);
}
Ok(())
}
fn set_width(&mut self, w: u32) {
fn set_width(&mut self, w: u32) -> LvResult<()> {
unsafe {
lvgl_sys::lv_obj_set_width(self.raw().as_mut(), w as lvgl_sys::lv_coord_t);
lvgl_sys::lv_obj_set_width(self.raw()?.as_mut(), w as lvgl_sys::lv_coord_t);
}
Ok(())
}
fn set_height(&mut self, h: u32) {
fn set_height(&mut self, h: u32) -> LvResult<()> {
unsafe {
lvgl_sys::lv_obj_set_height(self.raw().as_mut(), h as lvgl_sys::lv_coord_t);
lvgl_sys::lv_obj_set_height(self.raw()?.as_mut(), h as lvgl_sys::lv_coord_t);
}
Ok(())
}
fn set_align<C>(&mut self, base: &mut C, align: Align, x_mod: i32, y_mod: i32)
fn set_align<C>(&mut self, base: &mut C, align: Align, x_mod: i32, y_mod: i32) -> LvResult<()>
where
C: NativeObject,
{
unsafe {
lvgl_sys::lv_obj_align(
self.raw().as_mut(),
base.raw().as_mut(),
self.raw()?.as_mut(),
base.raw()?.as_mut(),
align.into(),
x_mod as lvgl_sys::lv_coord_t,
y_mod as lvgl_sys::lv_coord_t,
);
}
Ok(())
}
}
@ -128,25 +136,25 @@ macro_rules! define_object {
}
impl $item {
pub fn new<C>(parent: &mut C) -> Self
pub fn new<C>(parent: &mut C) -> $crate::LvResult<Self>
where
C: $crate::NativeObject,
{
unsafe {
let ptr = lvgl_sys::$create_fn(parent.raw().as_mut(), core::ptr::null_mut());
let raw = core::ptr::NonNull::new_unchecked(ptr);
let ptr = lvgl_sys::$create_fn(parent.raw()?.as_mut(), core::ptr::null_mut());
let raw = core::ptr::NonNull::new(ptr)?;
let core = <$crate::Obj as $crate::Widget>::from_raw(raw);
Self { core }
Ok(Self { core })
}
}
pub fn on_event<F>(&mut self, f: F)
pub fn on_event<F>(&mut self, f: F) -> $crate::LvResult<()>
where
F: FnMut(Self, $crate::support::Event<<Self as $crate::Widget>::SpecialEvent>),
{
use $crate::NativeObject;
unsafe {
let mut raw = self.raw();
let mut raw = self.raw()?;
let obj = raw.as_mut();
let user_closure = alloc::boxed::Box::new(f);
obj.user_data = alloc::boxed::Box::into_raw(user_closure) as *mut cty::c_void;
@ -155,11 +163,12 @@ macro_rules! define_object {
lvgl_sys::lv_event_cb_t::Some($crate::support::event_callback::<Self, F>),
);
}
Ok(())
}
}
impl $crate::NativeObject for $item {
fn raw(&self) -> core::ptr::NonNull<lvgl_sys::lv_obj_t> {
fn raw(&self) -> $crate::LvResult<core::ptr::NonNull<lvgl_sys::lv_obj_t>> {
self.core.raw()
}
}

View file

@ -1,4 +1,4 @@
use crate::{Color, State};
use crate::{Color, LvResult, State};
use alloc::boxed::Box;
use core::mem;
use cstr_core::CString;
@ -12,22 +12,9 @@ pub struct Style {
}
impl Style {
pub fn set_value_str(&mut self, state: State, value: &str) {
pub fn set_value_str(&mut self, state: State, value: &str) -> LvResult<()> {
let native_state: u32 = state.get_bits();
let string = CString::new(value).unwrap();
unsafe {
lvgl_sys::_lv_style_set_ptr(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_STR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
string.into_raw() as *mut cty::c_void,
);
}
}
pub fn set_font(&mut self, state: State, value: &str) {
let native_state: u32 = state.get_bits();
let string = CString::new(value).unwrap();
let string = CString::new(value)?;
unsafe {
lvgl_sys::_lv_style_set_ptr(
self.raw.as_mut(),
@ -36,6 +23,7 @@ impl Style {
string.into_raw() as *mut cty::c_void,
);
}
Ok(())
}
}

View file

@ -1,8 +1,32 @@
use crate::Widget;
use bitflags::_core::option::NoneError;
use core::convert::{TryFrom, TryInto};
use core::ptr::NonNull;
use cstr_core::NulError;
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
pub type LvResult<T> = Result<T, LvError>;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum LvError {
InvalidReference,
Uninitialized,
InvalidNulByteString,
AlreadyInUse,
}
impl From<NoneError> for LvError {
fn from(_: NoneError) -> Self {
LvError::InvalidReference
}
}
impl From<NulError> for LvError {
fn from(_: NulError) -> Self {
LvError::InvalidNulByteString
}
}
#[derive(Clone)]
pub struct Color {
pub(crate) raw: lvgl_sys::lv_color_t,

View file

@ -1,39 +1,42 @@
use crate::NativeObject;
use crate::{LvResult, NativeObject};
define_object!(Arc, lv_arc_create, part = ArcPart);
impl Arc {
/// Set the start angle, for the given arc part.
/// 0 degrees for the right, 90 degrees for the bottom, etc.
pub fn set_start_angle(&mut self, angle: u16, part: ArcPart) {
pub fn set_start_angle(&mut self, angle: u16, part: ArcPart) -> LvResult<()> {
match part {
ArcPart::Background => unsafe {
lvgl_sys::lv_arc_set_bg_start_angle(self.core.raw().as_mut(), angle)
lvgl_sys::lv_arc_set_bg_start_angle(self.core.raw()?.as_mut(), angle)
},
ArcPart::Indicator => unsafe {
lvgl_sys::lv_arc_set_start_angle(self.core.raw().as_mut(), angle)
lvgl_sys::lv_arc_set_start_angle(self.core.raw()?.as_mut(), angle)
},
}
Ok(())
}
/// Set the end angle, for the given arc part.
/// 0 degrees for the right, 90 degrees for the bottom, etc.
pub fn set_end_angle(&mut self, angle: u16, part: ArcPart) {
pub fn set_end_angle(&mut self, angle: u16, part: ArcPart) -> LvResult<()> {
match part {
ArcPart::Background => unsafe {
lvgl_sys::lv_arc_set_bg_start_angle(self.core.raw().as_mut(), angle)
lvgl_sys::lv_arc_set_bg_start_angle(self.core.raw()?.as_mut(), angle)
},
ArcPart::Indicator => unsafe {
lvgl_sys::lv_arc_set_end_angle(self.core.raw().as_mut(), angle)
lvgl_sys::lv_arc_set_end_angle(self.core.raw()?.as_mut(), angle)
},
}
Ok(())
}
/// Rotate the arc, `angle` degrees clockwise.
pub fn set_rotation(&mut self, angle: u16) {
pub fn set_rotation(&mut self, angle: u16) -> LvResult<()> {
unsafe {
lvgl_sys::lv_arc_set_rotation(self.core.raw().as_mut(), angle);
lvgl_sys::lv_arc_set_rotation(self.core.raw()?.as_mut(), angle);
}
Ok(())
}
}

View file

@ -1,21 +1,23 @@
use crate::support::Animation;
use crate::NativeObject;
use crate::{LvResult, NativeObject};
define_object!(Bar, lv_bar_create, part = BarPart);
impl Bar {
/// Set minimum and the maximum values of the bar
pub fn set_range(&mut self, min: i16, max: i16) {
pub fn set_range(&mut self, min: i16, max: i16) -> LvResult<()> {
unsafe {
lvgl_sys::lv_bar_set_range(self.core.raw().as_mut(), min, max);
lvgl_sys::lv_bar_set_range(self.core.raw()?.as_mut(), min, max);
}
Ok(())
}
/// Set a new value on the bar
pub fn set_value(&mut self, value: i16, anim: Animation) {
pub fn set_value(&mut self, value: i16, anim: Animation) -> LvResult<()> {
unsafe {
lvgl_sys::lv_bar_set_value(self.core.raw().as_mut(), value, anim.into());
lvgl_sys::lv_bar_set_value(self.core.raw()?.as_mut(), value, anim.into());
}
Ok(())
}
}

View file

@ -1,13 +1,14 @@
use crate::NativeObject;
use crate::{LvResult, NativeObject};
define_object!(Gauge, lv_gauge_create, part = GaugePart);
impl Gauge {
/// Set a new value on the gauge
pub fn set_value(&mut self, needle_id: u8, value: i32) {
pub fn set_value(&mut self, needle_id: u8, value: i32) -> LvResult<()> {
unsafe {
lvgl_sys::lv_gauge_set_value(self.core.raw().as_mut(), needle_id, value);
lvgl_sys::lv_gauge_set_value(self.core.raw()?.as_mut(), needle_id, value);
}
Ok(())
}
}

View file

@ -1,17 +1,18 @@
use crate::NativeObject;
use crate::{LvResult, NativeObject};
use cstr_core::CString;
define_object!(Label, lv_label_create);
impl Label {
pub fn set_text(&mut self, text: &str) {
pub fn set_text(&mut self, text: &str) -> LvResult<()> {
let text = CString::new(text).unwrap();
unsafe {
lvgl_sys::lv_label_set_text(self.core.raw().as_mut(), text.as_ptr());
lvgl_sys::lv_label_set_text(self.core.raw()?.as_mut(), text.as_ptr());
}
Ok(())
}
pub fn set_label_align(&mut self, align: LabelAlign) {
pub fn set_label_align(&mut self, align: LabelAlign) -> LvResult<()> {
let align = match align {
LabelAlign::Left => lvgl_sys::LV_LABEL_ALIGN_LEFT,
LabelAlign::Center => lvgl_sys::LV_LABEL_ALIGN_CENTER,
@ -19,14 +20,16 @@ impl Label {
LabelAlign::Auto => lvgl_sys::LV_LABEL_ALIGN_AUTO,
} as lvgl_sys::lv_label_align_t;
unsafe {
lvgl_sys::lv_label_set_align(self.core.raw().as_mut(), align);
lvgl_sys::lv_label_set_align(self.core.raw()?.as_mut(), align);
}
Ok(())
}
pub fn set_recolor(&mut self, recolor: bool) {
pub fn set_recolor(&mut self, recolor: bool) -> LvResult<()> {
unsafe {
lvgl_sys::lv_label_set_recolor(self.core.raw().as_mut(), recolor);
lvgl_sys::lv_label_set_recolor(self.core.raw()?.as_mut(), recolor);
}
Ok(())
}
}