Simplified API for display initialization

This commit is contained in:
Rafael Caricio 2021-05-31 00:34:12 +02:00
parent 802504ff9d
commit 2326c1fbc5
Signed by: rafaelcaricio
GPG key ID: 3C86DBCE8E93C947
10 changed files with 288 additions and 115 deletions

View file

@ -2,7 +2,7 @@ use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window}; use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window};
use lvgl; use lvgl;
use lvgl::display::{Display, DisplayBuffer, DisplayDriver}; use lvgl::display::Display;
type ColorSpace = Rgb565; type ColorSpace = Rgb565;
@ -17,7 +17,5 @@ fn main() {
// LVGL usage // LVGL usage
lvgl::init(); lvgl::init();
Display::register(embedded_graphics_display).unwrap();
let mut display_diver = DisplayDriver::new(DisplayBuffer::new(), embedded_graphics_display);
let gui = lvgl::disp_drv_register(&mut display_diver).unwrap();
} }

View file

@ -1,6 +1,6 @@
/** /**
* @file lv_conf.h * @file lv_conf.h
* * Configuration file for v7.10.1
*/ */
/* /*
@ -82,7 +82,7 @@ typedef int16_t lv_coord_t;
/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ /* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
# define LV_MEM_SIZE (1048576U) // 1Mb # define LV_MEM_SIZE (1048576U) // 1Mb
/* Complier prefix for a big array declaration */ /* Compiler prefix for a big array declaration */
# define LV_MEM_ATTR # define LV_MEM_ATTR
/* Set an address for the memory pool instead of allocating it as an array. /* Set an address for the memory pool instead of allocating it as an array.
@ -97,6 +97,10 @@ typedef int16_t lv_coord_t;
# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ # define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/
#endif /*LV_MEM_CUSTOM*/ #endif /*LV_MEM_CUSTOM*/
/* Use the standard memcpy and memset instead of LVGL's own functions.
* The standard functions might or might not be faster depending on their implementation. */
#define LV_MEMCPY_MEMSET_STD 0
/* Garbage Collector settings /* Garbage Collector settings
* Used if lvgl is binded to higher level language and the memory is managed by that language */ * Used if lvgl is binded to higher level language and the memory is managed by that language */
#define LV_ENABLE_GC 0 #define LV_ENABLE_GC 0
@ -123,14 +127,13 @@ typedef int16_t lv_coord_t;
#define LV_INDEV_DEF_DRAG_THROW 10 #define LV_INDEV_DEF_DRAG_THROW 10
/* Long press time in milliseconds. /* Long press time in milliseconds.
* Time to send `LV_EVENT_LONG_PRESSSED`) */ * Time to send `LV_EVENT_LONG_PRESSED`) */
#define LV_INDEV_DEF_LONG_PRESS_TIME 400 #define LV_INDEV_DEF_LONG_PRESS_TIME 400
/* Repeated trigger period in long press [ms] /* Repeated trigger period in long press [ms]
* Time between `LV_EVENT_LONG_PRESSED_REPEAT */ * Time between `LV_EVENT_LONG_PRESSED_REPEAT */
#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100 #define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100
/* Gesture threshold in pixels */ /* Gesture threshold in pixels */
#define LV_INDEV_DEF_GESTURE_LIMIT 50 #define LV_INDEV_DEF_GESTURE_LIMIT 50
@ -150,7 +153,7 @@ typedef void * lv_anim_user_data_t;
#endif #endif
/* 1: Enable shadow drawing*/ /* 1: Enable shadow drawing on rectangles*/
#define LV_USE_SHADOW 1 #define LV_USE_SHADOW 1
#if LV_USE_SHADOW #if LV_USE_SHADOW
/* Allow buffering some shadow calculation /* Allow buffering some shadow calculation
@ -160,6 +163,15 @@ typedef void * lv_anim_user_data_t;
#define LV_SHADOW_CACHE_SIZE 0 #define LV_SHADOW_CACHE_SIZE 0
#endif #endif
/*1: enable outline drawing on rectangles*/
#define LV_USE_OUTLINE 1
/*1: enable pattern drawing on rectangles*/
#define LV_USE_PATTERN 1
/*1: enable value string drawing on rectangles*/
#define LV_USE_VALUE_STR 1
/* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/ /* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/
#define LV_USE_BLEND_MODES 1 #define LV_USE_BLEND_MODES 1
@ -178,6 +190,22 @@ typedef void * lv_group_user_data_t;
/* 1: Enable GPU interface*/ /* 1: Enable GPU interface*/
#define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */ #define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */
#define LV_USE_GPU_STM32_DMA2D 0 #define LV_USE_GPU_STM32_DMA2D 0
/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include path of CMSIS header of target processor
e.g. "stm32f769xx.h" or "stm32f429xx.h" */
#define LV_GPU_DMA2D_CMSIS_INCLUDE
/*1: Use PXP for CPU off-load on NXP RTxxx platforms */
#define LV_USE_GPU_NXP_PXP 0
/*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c)
* and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol FSL_RTOS_FREE_RTOS
* has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected.
*0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init()
* */
#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0
/*1: Use VG-Lite for CPU offload on NXP RTxxx platforms */
#define LV_USE_GPU_NXP_VG_LITE 0
/* 1: Enable file system (might be required for images */ /* 1: Enable file system (might be required for images */
#define LV_USE_FILESYSTEM 1 #define LV_USE_FILESYSTEM 1
@ -194,6 +222,7 @@ typedef void * lv_fs_drv_user_data_t;
/*1: Use the functions and types from the older API if possible */ /*1: Use the functions and types from the older API if possible */
#define LV_USE_API_EXTENSION_V6 1 #define LV_USE_API_EXTENSION_V6 1
#define LV_USE_API_EXTENSION_V7 1
/*======================== /*========================
* Image decoder and cache * Image decoder and cache
@ -210,7 +239,7 @@ typedef void * lv_fs_drv_user_data_t;
* (I.e. no new image decoder is added) * (I.e. no new image decoder is added)
* With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. * With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
* However the opened images might consume additional RAM. * However the opened images might consume additional RAM.
* LV_IMG_CACHE_DEF_SIZE must be >= 1 */ * Set it to 0 to disable caching */
#define LV_IMG_CACHE_DEF_SIZE 1 #define LV_IMG_CACHE_DEF_SIZE 1
/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/ /*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/
@ -219,6 +248,10 @@ typedef void * lv_img_decoder_user_data_t;
/*===================== /*=====================
* Compiler settings * Compiler settings
*====================*/ *====================*/
/* For big endian systems set to 1 */
#define LV_BIG_ENDIAN_SYSTEM 0
/* Define a custom attribute to `lv_tick_inc` function */ /* Define a custom attribute to `lv_tick_inc` function */
#define LV_ATTRIBUTE_TICK_INC #define LV_ATTRIBUTE_TICK_INC
@ -228,9 +261,14 @@ typedef void * lv_img_decoder_user_data_t;
/* Define a custom attribute to `lv_disp_flush_ready` function */ /* Define a custom attribute to `lv_disp_flush_ready` function */
#define LV_ATTRIBUTE_FLUSH_READY #define LV_ATTRIBUTE_FLUSH_READY
/* Required alignment size for buffers */
#define LV_ATTRIBUTE_MEM_ALIGN_SIZE
/* With size optimization (-Os) the compiler might not align data to /* With size optimization (-Os) the compiler might not align data to
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed. * 4 or 8 byte boundary. Some HW may need even 32 or 64 bytes.
* E.g. __attribute__((aligned(4))) */ * This alignment will be explicitly applied where needed.
* LV_ATTRIBUTE_MEM_ALIGN_SIZE should be used to specify required align size.
* E.g. __attribute__((aligned(LV_ATTRIBUTE_MEM_ALIGN_SIZE))) */
#define LV_ATTRIBUTE_MEM_ALIGN #define LV_ATTRIBUTE_MEM_ALIGN
/* Attribute to mark large constant arrays for example /* Attribute to mark large constant arrays for example
@ -249,6 +287,10 @@ typedef void * lv_img_decoder_user_data_t;
*/ */
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning #define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning
/* Prefix variables that are used in GPU accelerated operations, often these need to be
* placed in RAM sections that are DMA accessible */
#define LV_ATTRIBUTE_DMA
/*=================== /*===================
* HAL settings * HAL settings
*==================*/ *==================*/
@ -257,8 +299,8 @@ typedef void * lv_img_decoder_user_data_t;
* It removes the need to manually update the tick with `lv_tick_inc`) */ * It removes the need to manually update the tick with `lv_tick_inc`) */
#define LV_TICK_CUSTOM 0 #define LV_TICK_CUSTOM 0
#if LV_TICK_CUSTOM == 1 #if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/ #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/ #endif /*LV_TICK_CUSTOM*/
typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/ typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/
@ -293,7 +335,7 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
* If an invalid parameter is found an error log message is printed and * If an invalid parameter is found an error log message is printed and
* the MCU halts at the error. (`LV_USE_LOG` should be enabled) * the MCU halts at the error. (`LV_USE_LOG` should be enabled)
* If you are debugging the MCU you can pause * If you are debugging the MCU you can pause
* the debugger to see exactly where the issue is. * the debugger to see exactly where the issue is.
* *
* The behavior of asserts can be overwritten by redefining them here. * The behavior of asserts can be overwritten by redefining them here.
* E.g. #define LV_ASSERT_MEM(p) <my_assert_code> * E.g. #define LV_ASSERT_MEM(p) <my_assert_code>
@ -328,17 +370,19 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
* FONT USAGE * FONT USAGE
*===================*/ *===================*/
/* The built-in fonts contains the ASCII range and some Symbols with 4 bit-per-pixel. /* The built-in fonts contains the ASCII range and some Symbols with 4 bit-per-pixel.
* The symbols are available via `LV_SYMBOL_...` defines * The symbols are available via `LV_SYMBOL_...` defines
* More info about fonts: https://docs.lvgl.com/#Fonts * More info about fonts: https://docs.lvgl.io/v7/en/html/overview/font.html
* To create a new font go to: https://lvgl.com/ttf-font-to-c-array * To create a new font go to: https://lvgl.com/ttf-font-to-c-array
*/ */
/* Montserrat fonts with bpp = 4 /* Montserrat fonts with bpp = 4
* https://fonts.google.com/specimen/Montserrat */ * https://fonts.google.com/specimen/Montserrat */
#define LV_FONT_MONTSERRAT_8 0
#define LV_FONT_MONTSERRAT_10 0
#define LV_FONT_MONTSERRAT_12 0 #define LV_FONT_MONTSERRAT_12 0
#define LV_FONT_MONTSERRAT_14 0 #define LV_FONT_MONTSERRAT_14 1
#define LV_FONT_MONTSERRAT_16 1 #define LV_FONT_MONTSERRAT_16 0
#define LV_FONT_MONTSERRAT_18 0 #define LV_FONT_MONTSERRAT_18 0
#define LV_FONT_MONTSERRAT_20 0 #define LV_FONT_MONTSERRAT_20 0
#define LV_FONT_MONTSERRAT_22 0 #define LV_FONT_MONTSERRAT_22 0
@ -365,6 +409,7 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
/*Pixel perfect monospace font /*Pixel perfect monospace font
* http://pelulamu.net/unscii/ */ * http://pelulamu.net/unscii/ */
#define LV_FONT_UNSCII_8 0 #define LV_FONT_UNSCII_8 0
#define LV_FONT_UNSCII_16 0
/* Optionally declare your custom fonts here. /* Optionally declare your custom fonts here.
* You can use these fonts as default font too * You can use these fonts as default font too
@ -379,11 +424,20 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
* but with > 10,000 characters if you see issues probably you need to enable it.*/ * but with > 10,000 characters if you see issues probably you need to enable it.*/
#define LV_FONT_FMT_TXT_LARGE 0 #define LV_FONT_FMT_TXT_LARGE 0
/* Enables/disables support for compressed fonts. If it's disabled, compressed
* glyphs cannot be processed by the library and won't be rendered.
*/
#define LV_USE_FONT_COMPRESSED 1
/* Enable subpixel rendering */
#define LV_USE_FONT_SUBPX 1
#if LV_USE_FONT_SUBPX
/* Set the pixel order of the display. /* Set the pixel order of the display.
* Important only if "subpx fonts" are used. * Important only if "subpx fonts" are used.
* With "normal" font it doesn't matter. * With "normal" font it doesn't matter.
*/ */
#define LV_FONT_SUBPX_BGR 0 #define LV_FONT_SUBPX_BGR 0
#endif
/*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/ /*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_font_user_data_t; typedef void * lv_font_user_data_t;
@ -396,34 +450,37 @@ typedef void * lv_font_user_data_t;
/* No theme, you can apply your styles as you need /* No theme, you can apply your styles as you need
* No flags. Set LV_THEME_DEFAULT_FLAG 0 */ * No flags. Set LV_THEME_DEFAULT_FLAG 0 */
#define LV_USE_THEME_EMPTY 1 #define LV_USE_THEME_EMPTY 1
/*Simple to the create your theme based on it /*Simple to the create your theme based on it
* No flags. Set LV_THEME_DEFAULT_FLAG 0 */ * No flags. Set LV_THEME_DEFAULT_FLAG 0 */
#define LV_USE_THEME_TEMPLATE 1 #define LV_USE_THEME_TEMPLATE 1
/* A fast and impressive theme. /* A fast and impressive theme.
* Flags: * Flags:
* LV_THEME_MATERIAL_FLAG_LIGHT: light theme * LV_THEME_MATERIAL_FLAG_LIGHT: light theme
* LV_THEME_MATERIAL_FLAG_DARK: dark theme*/ * LV_THEME_MATERIAL_FLAG_DARK: dark theme
#define LV_USE_THEME_MATERIAL 1 * LV_THEME_MATERIAL_FLAG_NO_TRANSITION: disable transitions (state change animations)
* LV_THEME_MATERIAL_FLAG_NO_FOCUS: disable indication of focused state)
* */
#define LV_USE_THEME_MATERIAL 1
/* Mono-color theme for monochrome displays. /* Mono-color theme for monochrome displays.
* If LV_THEME_DEFAULT_COLOR_PRIMARY is LV_COLOR_BLACK the * If LV_THEME_DEFAULT_COLOR_PRIMARY is LV_COLOR_BLACK the
* texts and borders will be black and the background will be * texts and borders will be black and the background will be
* white. Else the colors are inverted. * white. Else the colors are inverted.
* No flags. Set LV_THEME_DEFAULT_FLAG 0 */ * No flags. Set LV_THEME_DEFAULT_FLAG 0 */
#define LV_USE_THEME_MONO 1 #define LV_USE_THEME_MONO 1
#define LV_THEME_DEFAULT_INCLUDE <stdint.h> /*Include a header for the init. function*/ #define LV_THEME_DEFAULT_INCLUDE <stdint.h> /*Include a header for the init. function*/
#define LV_THEME_DEFAULT_INIT lv_theme_material_init #define LV_THEME_DEFAULT_INIT lv_theme_material_init
#define LV_THEME_DEFAULT_COLOR_PRIMARY LV_COLOR_RED #define LV_THEME_DEFAULT_COLOR_PRIMARY lv_color_hex(0x01a2b1)
#define LV_THEME_DEFAULT_COLOR_SECONDARY LV_COLOR_BLUE #define LV_THEME_DEFAULT_COLOR_SECONDARY lv_color_hex(0x44d1b6)
#define LV_THEME_DEFAULT_FLAG LV_THEME_MATERIAL_FLAG_LIGHT #define LV_THEME_DEFAULT_FLAG LV_THEME_MATERIAL_FLAG_LIGHT
#define LV_THEME_DEFAULT_FONT_SMALL &lv_font_montserrat_16 #define LV_THEME_DEFAULT_FONT_SMALL &lv_font_montserrat_14
#define LV_THEME_DEFAULT_FONT_NORMAL &lv_font_montserrat_16 #define LV_THEME_DEFAULT_FONT_NORMAL &lv_font_montserrat_14
#define LV_THEME_DEFAULT_FONT_SUBTITLE &lv_font_montserrat_16 #define LV_THEME_DEFAULT_FONT_SUBTITLE &lv_font_montserrat_14
#define LV_THEME_DEFAULT_FONT_TITLE &lv_font_montserrat_16 #define LV_THEME_DEFAULT_FONT_TITLE &lv_font_montserrat_14
/*================= /*=================
* Text settings * Text settings
@ -456,7 +513,7 @@ typedef void * lv_font_user_data_t;
/* Support bidirectional texts. /* Support bidirectional texts.
* Allows mixing Left-to-Right and Right-to-Left texts. * Allows mixing Left-to-Right and Right-to-Left texts.
* The direction will be processed according to the Unicode Bidirectioanl Algorithm: * The direction will be processed according to the Unicode Bidirectional Algorithm:
* https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
#define LV_USE_BIDI 0 #define LV_USE_BIDI 0
#if LV_USE_BIDI #if LV_USE_BIDI
@ -498,7 +555,7 @@ typedef void * lv_obj_user_data_t;
#endif #endif
#endif #endif
/*1: enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ /*1: enable `lv_obj_realign()` based on `lv_obj_align()` parameters*/
#define LV_USE_OBJ_REALIGN 1 #define LV_USE_OBJ_REALIGN 1
/* Enable to make the object clickable on a larger area. /* Enable to make the object clickable on a larger area.
@ -529,6 +586,9 @@ typedef void * lv_obj_user_data_t;
/*Calendar (dependencies: -)*/ /*Calendar (dependencies: -)*/
#define LV_USE_CALENDAR 1 #define LV_USE_CALENDAR 1
#if LV_USE_CALENDAR
# define LV_CALENDAR_WEEK_STARTS_MONDAY 0
#endif
/*Canvas (dependencies: lv_img)*/ /*Canvas (dependencies: lv_img)*/
#define LV_USE_CANVAS 1 #define LV_USE_CANVAS 1
@ -613,7 +673,7 @@ typedef void * lv_obj_user_data_t;
* 1: Some extra precision * 1: Some extra precision
* 2: Best precision * 2: Best precision
*/ */
# define LV_LINEMETER_PRECISE 0 # define LV_LINEMETER_PRECISE 1
#endif #endif
/*Mask (dependencies: -)*/ /*Mask (dependencies: -)*/
@ -667,6 +727,7 @@ typedef void * lv_obj_user_data_t;
#define LV_USE_TABLE 1 #define LV_USE_TABLE 1
#if LV_USE_TABLE #if LV_USE_TABLE
# define LV_TABLE_COL_MAX 12 # define LV_TABLE_COL_MAX 12
# define LV_TABLE_CELL_STYLE_CNT 4
#endif #endif
/*Tab (dependencies: lv_page, lv_btnm)*/ /*Tab (dependencies: lv_page, lv_btnm)*/

View file

@ -17,6 +17,8 @@ cty = "0.2.1"
embedded-graphics = "0.6.2" embedded-graphics = "0.6.2"
cstr_core = "0.2.3" cstr_core = "0.2.3"
bitflags = "1.2.1" bitflags = "1.2.1"
parking_lot = "0.11.1"
lazy_static = "1.4.0"
[features] [features]
alloc = ["cstr_core/alloc"] alloc = ["cstr_core/alloc"]
@ -35,22 +37,18 @@ heapless = "0.5.5"
[[example]] [[example]]
name = "app" name = "app"
path = "../examples/app.rs" path = "../examples/app.rs"
required-features = ["alloc"]
[[example]] [[example]]
name = "demo" name = "demo"
path = "../examples/demo.rs" path = "../examples/demo.rs"
required-features = ["alloc"]
[[example]] [[example]]
name = "bar" name = "bar"
path = "../examples/bar.rs" path = "../examples/bar.rs"
required-features = ["alloc"]
[[example]] [[example]]
name = "button_click" name = "button_click"
path = "../examples/button_click.rs" path = "../examples/button_click.rs"
required-features = ["alloc"]
[[example]] [[example]]
name = "gauge" name = "gauge"
@ -59,4 +57,3 @@ path = "../examples/gauge.rs"
[[example]] [[example]]
name = "arc" name = "arc"
path = "../examples/arc.rs" path = "../examples/arc.rs"
required-features = ["lvgl_alloc"]

View file

@ -9,12 +9,12 @@ pub struct LvglAlloc;
unsafe impl GlobalAlloc for LvglAlloc { unsafe impl GlobalAlloc for LvglAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// Make sure LVGL is initialized! // Make sure LVGL is initialized!
crate::lvgl_init(); crate::init();
lvgl_sys::lv_mem_alloc(layout.size() as lvgl_sys::size_t) as *mut u8 lvgl_sys::lv_mem_alloc(layout.size() as lvgl_sys::size_t) as *mut u8
} }
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
crate::lvgl_init(); crate::init();
lvgl_sys::lv_mem_free(ptr as *const cty::c_void) lvgl_sys::lv_mem_free(ptr as *const cty::c_void)
} }
} }

View file

@ -1,8 +1,11 @@
use crate::{Color, LvError, LvResult, Obj}; use crate::functions::CoreError;
use crate::Box;
use crate::{disp_drv_register, disp_get_default, get_str_act};
use crate::{Color, Obj};
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{ManuallyDrop, MaybeUninit}; use core::mem::MaybeUninit;
use core::ptr;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::{ptr, result};
use embedded_graphics::drawable; use embedded_graphics::drawable;
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
@ -11,29 +14,51 @@ const REFRESH_BUFFER_LEN: usize = 2;
// Declare a buffer for the refresh rate // Declare a buffer for the refresh rate
pub(crate) 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;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DisplayError { pub enum DisplayError {
NotAvailable,
FailedToRegister, FailedToRegister,
NotRegistered, NotRegistered,
} }
type Result<T> = result::Result<T, DisplayError>;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Display { pub struct Display {
disp: NonNull<lvgl_sys::lv_disp_t>, pub(crate) disp: NonNull<lvgl_sys::lv_disp_t>,
} }
impl Display { impl Display {
pub(crate) fn from_raw(disp: NonNull<lvgl_sys::lv_disp_t>) -> Self { pub(crate) fn from_raw(disp: NonNull<lvgl_sys::lv_disp_t>) -> Self {
Self { disp } Self { disp }
} }
pub fn register<C>(embedded_graphics_display: impl DrawTarget<C>) -> Result<Self>
where
C: PixelColor + From<Color>,
{
let mut display_diver = DisplayDriver::new(DisplayBuffer::new(), embedded_graphics_display);
Ok(disp_drv_register(&mut display_diver)?)
}
pub fn get_str_act(&self) -> Result<Obj> {
Ok(get_str_act(Some(&self))?)
}
}
impl Default for Display {
fn default() -> Self {
disp_get_default().expect("LVGL must be initialized")
}
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct DefaultDisplay {} pub struct DefaultDisplay {}
impl DefaultDisplay { impl DefaultDisplay {
pub fn get_screen_active() -> Result<Obj, DisplayError> { /// Gets the screen active of the default display.
Err(DisplayError::NotRegistered) pub fn get_scr_act() -> Result<Obj> {
Ok(get_str_act(None)?)
} }
} }
@ -46,11 +71,11 @@ impl DisplayBuffer {
pub fn new() -> Self { pub fn new() -> Self {
let disp_buf = unsafe { let disp_buf = unsafe {
let mut disp_buf = MaybeUninit::uninit(); let mut disp_buf = MaybeUninit::uninit();
let mut refresh_buffer = ManuallyDrop::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]); let refresh_buffer = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]);
lvgl_sys::lv_disp_buf_init( lvgl_sys::lv_disp_buf_init(
disp_buf.as_mut_ptr(), disp_buf.as_mut_ptr(),
refresh_buffer.as_mut_ptr() as *mut cty::c_void, Box::into_raw(refresh_buffer) as *mut cty::c_void,
ptr::null_mut(), ptr::null_mut(),
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32, lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
); );
@ -78,20 +103,26 @@ where
C: PixelColor + From<Color>, C: PixelColor + From<Color>,
{ {
pub fn new(display_buffer: DisplayBuffer, native_display: T) -> Self { pub fn new(display_buffer: DisplayBuffer, native_display: T) -> Self {
let mut disp_buf = ManuallyDrop::new(display_buffer.disp_buf);
let mut native_display = ManuallyDrop::new(DisplayUserData {
display: native_display,
phantom: PhantomData,
});
let mut disp_drv = unsafe { let mut disp_drv = unsafe {
let mut disp_drv = MaybeUninit::uninit(); let mut disp_drv = MaybeUninit::uninit();
lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr()); lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr());
disp_drv.assume_init() disp_drv.assume_init()
}; };
disp_drv.buffer = &mut *disp_buf as *mut lvgl_sys::lv_disp_buf_t;
disp_drv.user_data = &mut native_display as *mut _ as lvgl_sys::lv_disp_drv_user_data_t; // We need to add to a `Box`, so it's copied to a memory location in the "heap" (LVGL statically allocated heap).
let disp_buf = Box::new(display_buffer.disp_buf);
disp_drv.buffer = Box::into_raw(disp_buf) as *mut lvgl_sys::lv_disp_buf_t;
let native_display = Box::new(DisplayUserData {
display: native_display,
phantom: PhantomData,
});
disp_drv.user_data =
Box::into_raw(native_display) as *mut _ as lvgl_sys::lv_disp_drv_user_data_t;
disp_drv.flush_cb = Some(disp_flush_trampoline::<T, C>); disp_drv.flush_cb = Some(disp_flush_trampoline::<T, C>);
// We do not store any memory that can be accidentally deallocated by on the Rust side.
Self { Self {
disp_drv, disp_drv,
phantom_color: PhantomData, phantom_color: PhantomData,
@ -147,16 +178,49 @@ unsafe extern "C" fn disp_flush_trampoline<T, C>(
} }
} }
// impl Default for DisplayDriver { impl From<CoreError> for DisplayError {
// fn default() -> Self { fn from(err: CoreError) -> Self {
// Self::new(DisplayBuffer::new()) use DisplayError::*;
// } match err {
// } CoreError::ResourceNotAvailable => NotAvailable,
CoreError::OperationFailed => NotAvailable,
pub struct DisplayDriverBuilder { }
disp_buf: Option<DisplayBuffer>, }
} }
impl DisplayDriverBuilder { #[cfg(test)]
pub fn with_callback() {} mod tests {
use super::*;
use crate::tests;
#[test]
fn get_scr_act_return_display() {
tests::initialize_test();
let _screen = get_str_act(None).expect("We can get the active screen");
}
#[test]
fn get_default_display() {
tests::initialize_test();
let display = Display::default();
let _screen_direct = display
.get_str_act()
.expect("Return screen directly from the display instance");
let _screen_default =
DefaultDisplay::get_scr_act().expect("Return screen from the default display");
}
#[test]
fn register_display_directly() -> Result<()> {
tests::initialize_test();
let display = Display::default();
let _screen = display
.get_str_act()
.expect("Return screen directly from the display instance");
Ok(())
}
} }

View file

@ -1,16 +1,44 @@
use crate::display::{Display, DisplayDriver, DisplayError}; use crate::display::{Display, DisplayDriver};
use crate::Color; use crate::{Color, Obj, Widget};
use core::ptr::NonNull; use core::ptr::NonNull;
use embedded_graphics::drawable; use core::{ptr, result};
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum CoreError {
ResourceNotAvailable,
OperationFailed,
}
type Result<T> = result::Result<T, CoreError>;
/// Register own buffer
pub fn disp_drv_register<C: PixelColor + From<Color>, T: DrawTarget<C>>( pub fn disp_drv_register<C: PixelColor + From<Color>, T: DrawTarget<C>>(
disp_drv: &mut DisplayDriver<T, C>, disp_drv: &mut DisplayDriver<T, C>,
) -> Result<Display, DisplayError> { ) -> Result<Display> {
let disp_ptr = unsafe { let disp_ptr = unsafe {
lvgl_sys::lv_disp_drv_register(&mut disp_drv.disp_drv as *mut lvgl_sys::lv_disp_drv_t) lvgl_sys::lv_disp_drv_register(&mut disp_drv.disp_drv as *mut lvgl_sys::lv_disp_drv_t)
}; };
Ok(Display::from_raw( Ok(Display::from_raw(
NonNull::new(disp_ptr).ok_or(DisplayError::FailedToRegister)?, NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?,
))
}
pub(crate) fn disp_get_default() -> Result<Display> {
let disp_ptr = unsafe { lvgl_sys::lv_disp_get_default() };
Ok(Display::from_raw(
NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?,
))
}
pub(crate) fn get_str_act(disp: Option<&Display>) -> Result<Obj> {
let scr_ptr = unsafe {
lvgl_sys::lv_disp_get_scr_act(
disp.map(|d| d.disp.as_ptr())
.unwrap_or(ptr::null_mut() as *mut lvgl_sys::lv_disp_t),
)
};
Ok(Obj::from_raw(
NonNull::new(scr_ptr).ok_or(CoreError::ResourceNotAvailable)?,
)) ))
} }

View file

@ -17,6 +17,12 @@
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[macro_use]
mod lv_core;
#[cfg(feature = "lvgl_alloc")] #[cfg(feature = "lvgl_alloc")]
extern crate alloc; extern crate alloc;
@ -31,14 +37,6 @@ use ::alloc::boxed::Box;
#[cfg(feature = "lvgl_alloc")] #[cfg(feature = "lvgl_alloc")]
mod allocator; mod allocator;
pub mod display;
mod functions;
mod support;
mod ui;
#[macro_use]
mod lv_core;
pub mod widgets;
#[cfg(not(feature = "lvgl_alloc"))] #[cfg(not(feature = "lvgl_alloc"))]
pub(crate) mod mem; pub(crate) mod mem;
@ -49,18 +47,25 @@ pub(crate) mod mem;
#[cfg(not(feature = "lvgl_alloc"))] #[cfg(not(feature = "lvgl_alloc"))]
use crate::mem::Box; use crate::mem::Box;
pub mod display;
mod functions;
mod support;
mod ui;
pub mod widgets;
use core::sync::atomic::{AtomicBool, Ordering};
pub use functions::*; pub use functions::*;
pub use lv_core::*; pub use lv_core::*;
use parking_lot::Mutex;
pub use support::*; pub use support::*;
pub use ui::*; pub use ui::*;
use core::sync::atomic::{AtomicBool, Ordering}; lazy_static! {
static ref MUTEX: Mutex<AtomicBool> = Mutex::new(AtomicBool::new(false));
// Initialize LVGL only once. }
static LVGL_INITIALIZED: AtomicBool = AtomicBool::new(false);
pub fn init() { pub fn init() {
if LVGL_INITIALIZED let initialized = MUTEX.lock();
if initialized
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok() .is_ok()
{ {
@ -69,3 +74,24 @@ pub fn init() {
} }
} }
} }
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::display::Display;
use embedded_graphics::mock_display::MockDisplay;
use embedded_graphics::pixelcolor::Rgb565;
pub(crate) fn initialize_test() {
init();
static RUN_ONCE: Mutex<Option<u8>> = parking_lot::const_mutex(None);
let mut run_once = RUN_ONCE.lock();
if run_once.is_none() {
let embedded_graphics_display: MockDisplay<Rgb565> = Default::default();
let _ = Display::register(embedded_graphics_display).unwrap();
*run_once = Some(1);
}
}
}

View file

@ -35,10 +35,7 @@ pub trait Widget: NativeObject {
/// Construct an instance of the object from a raw pointer. /// Construct an instance of the object from a raw pointer.
/// ///
/// # Safety fn from_raw(raw_pointer: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self;
/// Provided the LVGL library can allocate memory this should be safe.
///
unsafe fn from_raw(raw_pointer: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self;
fn add_style(&self, part: Self::Part, style: Style) -> LvResult<()> { fn add_style(&self, part: Self::Part, style: Style) -> LvResult<()> {
unsafe { unsafe {
@ -104,7 +101,7 @@ impl Widget for Obj {
type SpecialEvent = (); type SpecialEvent = ();
type Part = Part; type Part = Part;
unsafe fn from_raw(raw: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self { fn from_raw(raw: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
Self { raw: raw.as_ptr() } Self { raw: raw.as_ptr() }
} }
} }
@ -167,7 +164,7 @@ macro_rules! define_object {
type SpecialEvent = $event_type; type SpecialEvent = $event_type;
type Part = $part_type; type Part = $part_type;
unsafe fn from_raw(raw_pointer: core::ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self { fn from_raw(raw_pointer: core::ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
Self { Self {
core: $crate::Obj::from_raw(raw_pointer), core: $crate::Obj::from_raw(raw_pointer),
} }

View file

@ -11,7 +11,7 @@ pub(crate) struct Box<T>(NonNull<T>);
impl<T> Box<T> { impl<T> Box<T> {
/// Allocate memory using LVGL memory API and place `T` in the LVGL tracked memory. /// Allocate memory using LVGL memory API and place `T` in the LVGL tracked memory.
pub fn new(value: T) -> Box<T> { pub fn new(value: T) -> Self {
let size = mem::size_of::<T>(); let size = mem::size_of::<T>();
let inner = unsafe { let inner = unsafe {
let ptr = lvgl_sys::lv_mem_alloc(size as lvgl_sys::size_t) as *mut T; let ptr = lvgl_sys::lv_mem_alloc(size as lvgl_sys::size_t) as *mut T;
@ -29,15 +29,15 @@ impl<T> Box<T> {
p p
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
panic!("Could not allocate memory {} bytes", size); panic!("Could not allocate memory {} bytes: {:?}", size, mem_info());
}) })
}; };
Box(inner) Self(inner)
} }
pub fn into_raw(self) -> *mut T { pub fn into_raw(self) -> *mut T {
let b = mem::ManuallyDrop::new(self); let b = mem::ManuallyDrop::new(self.0);
b.0.as_ptr() b.as_ptr()
} }
} }
@ -69,14 +69,33 @@ impl<T> AsMut<T> for Box<T> {
} }
} }
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(&mut info as *mut _);
}
info
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::mem::mem_info;
use crate::*;
use std::vec::Vec; use std::vec::Vec;
#[test] #[test]
fn place_value_in_lv_mem() { fn place_value_in_lv_mem() {
crate::lvgl_init(); tests::initialize_test();
let v = Box::new(5); let v = Box::new(5);
drop(v); drop(v);
@ -86,7 +105,7 @@ mod test {
#[test] #[test]
fn place_complex_value_in_lv_mem() { fn place_complex_value_in_lv_mem() {
crate::lvgl_init(); tests::initialize_test();
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
@ -135,21 +154,4 @@ mod test {
// If this fails, we are leaking memory! BOOM! \o/ // If this fails, we are leaking memory! BOOM! \o/
assert_eq!(initial_mem_info.free_size, final_info.free_size) assert_eq!(initial_mem_info.free_size, final_info.free_size)
} }
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(&mut info as *mut _);
}
info
}
} }

View file

@ -1,7 +1,7 @@
use crate::Box; use crate::Box;
use crate::{Color, Event, LvError, LvResult, Obj, Widget}; use crate::{Color, Event, LvError, LvResult, Obj, Widget};
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{ManuallyDrop, MaybeUninit}; use core::mem::MaybeUninit;
use core::ptr; use core::ptr;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};