Rust bindings API review #51
3
.github/workflows/rust.yml
vendored
|
@ -30,4 +30,5 @@ jobs:
|
|||
run: cargo build --verbose
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
# LVGL is not thread safe, we need to run tests sequentially
|
||||
run: cargo test --verbose -- --nocapture --test-threads 1
|
||||
|
|
40
examples/app.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window};
|
||||
use lvgl;
|
||||
use lvgl::widgets::Label;
|
||||
use lvgl::{Display, DrawBuffer};
|
||||
use parking_lot::Mutex;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
type ColorSpace = Rgb565;
|
||||
|
||||
fn main() {
|
||||
let embedded_graphics_display: SimulatorDisplay<ColorSpace> = SimulatorDisplay::new(Size::new(
|
||||
lvgl::DISP_HOR_RES as u32,
|
||||
lvgl::DISP_VER_RES as u32,
|
||||
));
|
||||
|
||||
let output_settings = OutputSettingsBuilder::new().scale(2).build();
|
||||
let mut window = Window::new("App Example", &output_settings);
|
||||
|
||||
let mut shared_native_display = Arc::new(Mutex::new(embedded_graphics_display));
|
||||
|
||||
// LVGL usage
|
||||
lvgl::init();
|
||||
|
||||
const REFRESH_BUFFER_SIZE: usize = lvgl::DISP_HOR_RES * lvgl::DISP_VER_RES / 10;
|
||||
static DRAW_BUFFER: DrawBuffer<REFRESH_BUFFER_SIZE> = DrawBuffer::new();
|
||||
|
||||
|
||||
let display = Display::register(&DRAW_BUFFER, {
|
||||
let shared_display = Arc::clone(&shared_native_display);
|
||||
move |update| {
|
||||
let mut embedded_graphics_display = shared_display.lock();
|
||||
embedded_graphics_display.draw_iter(update.as_pixels());
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let label: Label = "Nice!".into();
|
||||
}
|
|
@ -4,12 +4,16 @@ use embedded_graphics::prelude::*;
|
|||
use embedded_graphics_simulator::{
|
||||
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
|
||||
};
|
||||
use lvgl::display::Display;
|
||||
use lvgl::style::Style;
|
||||
use lvgl::widgets::{Arc, Label, LabelAlign};
|
||||
use lvgl::{self, Align, Color, Part, State, UI};
|
||||
use lvgl::{self, Align, Color, Part, State};
|
||||
use lvgl::{LvError, Widget};
|
||||
use lvgl_sys;
|
||||
use std::time::Instant;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc as SyncArc;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
fn mem_info() -> lvgl_sys::lv_mem_monitor_t {
|
||||
let mut info = lvgl_sys::lv_mem_monitor_t {
|
||||
|
@ -36,7 +40,9 @@ fn main() -> Result<(), LvError> {
|
|||
}
|
||||
|
||||
fn run_arc_demo() -> Result<(), LvError> {
|
||||
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||
lvgl::init();
|
||||
|
||||
let embedded_graphics_display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||
lvgl_sys::LV_HOR_RES_MAX,
|
||||
lvgl_sys::LV_VER_RES_MAX,
|
||||
));
|
||||
|
@ -44,52 +50,60 @@ fn run_arc_demo() -> Result<(), LvError> {
|
|||
let output_settings = OutputSettingsBuilder::new().scale(2).build();
|
||||
let mut window = Window::new("Arc Example", &output_settings);
|
||||
|
||||
let mut ui = UI::init()?;
|
||||
let shared_native_display = SyncArc::new(Mutex::new(embedded_graphics_display));
|
||||
let display = Display::register_shared(&shared_native_display)?;
|
||||
|
||||
// Implement and register your display:
|
||||
ui.disp_drv_register(display)?;
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = ui.scr_act()?;
|
||||
let mut screen = display.get_str_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, &mut screen_style)?;
|
||||
|
||||
// Create the arc object
|
||||
let mut arc = Arc::new(&mut screen)?;
|
||||
let mut arc = Arc::new()?;
|
||||
arc.set_size(150, 150)?;
|
||||
arc.set_align(&mut screen, Align::Center, 0, 10)?;
|
||||
arc.set_start_angle(135)?;
|
||||
arc.set_end_angle(135)?;
|
||||
|
||||
let mut loading_lbl = Label::new(&mut screen)?;
|
||||
let mut loading_lbl = Label::new()?;
|
||||
loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
|
||||
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, &mut loading_style)?;
|
||||
|
||||
let mut angle = 0;
|
||||
let mut forward = true;
|
||||
let mut i = 0;
|
||||
|
||||
let mut loop_started = Instant::now();
|
||||
// LVGL timer thread
|
||||
thread::spawn(|| {
|
||||
let interval = Duration::from_millis(5);
|
||||
loop {
|
||||
thread::sleep(interval);
|
||||
lvgl::tick_inc(interval);
|
||||
}
|
||||
});
|
||||
|
||||
'running: loop {
|
||||
if i > 270 {
|
||||
forward = if forward { false } else { true };
|
||||
i = 1;
|
||||
println!("meminfo running: {:?}", mem_info());
|
||||
println!("mem info running: {:?}", mem_info());
|
||||
}
|
||||
angle = if forward { angle + 1 } else { angle - 1 };
|
||||
arc.set_end_angle(angle + 135)?;
|
||||
i += 1;
|
||||
|
||||
ui.task_handler();
|
||||
window.update(ui.get_display_ref().unwrap());
|
||||
lvgl::task_handler();
|
||||
{
|
||||
let eg_display = shared_native_display.lock();
|
||||
window.update(&eg_display);
|
||||
}
|
||||
|
||||
for event in window.events() {
|
||||
match event {
|
||||
|
@ -97,9 +111,7 @@ fn run_arc_demo() -> Result<(), LvError> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ui.tick_inc(loop_started.elapsed());
|
||||
loop_started = Instant::now();
|
||||
thread::sleep(Duration::from_millis(15));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use cstr_core::CString;
|
||||
use embedded_graphics::drawable;
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics_simulator::{
|
||||
|
@ -7,61 +8,91 @@ use embedded_graphics_simulator::{
|
|||
use lvgl;
|
||||
use lvgl::style::Style;
|
||||
use lvgl::widgets::{Label, LabelAlign};
|
||||
use lvgl::{Align, Color, LvError, Part, State, Widget, UI};
|
||||
use lvgl::{Align, Color, DefaultDisplay, Display, DrawBuffer, LvError, Part, State, Widget};
|
||||
use lvgl_sys;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc as SyncArc;
|
||||
use std::thread;
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
fn main() -> Result<(), LvError> {
|
||||
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||
lvgl_sys::LV_HOR_RES_MAX,
|
||||
lvgl_sys::LV_VER_RES_MAX,
|
||||
let embedded_graphics_display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||
lvgl::DISP_HOR_RES as u32,
|
||||
lvgl::DISP_VER_RES as u32,
|
||||
));
|
||||
|
||||
let output_settings = OutputSettingsBuilder::new().scale(2).build();
|
||||
let output_settings = OutputSettingsBuilder::new().scale(1).build();
|
||||
let mut window = Window::new("PineTime", &output_settings);
|
||||
|
||||
let mut ui = UI::init()?;
|
||||
let shared_native_display = SyncArc::new(Mutex::new(embedded_graphics_display));
|
||||
|
||||
// Implement and register your display:
|
||||
ui.disp_drv_register(display).unwrap();
|
||||
// LVGL-rs usage starts here
|
||||
lvgl::init();
|
||||
|
||||
// LVGL will render the graphics here first, and seed the rendered image to the
|
||||
// display. The buffer size can be set freely but 1/10 screen size is a good starting point.
|
||||
const REFRESH_BUFFER_SIZE: usize = lvgl::DISP_HOR_RES * lvgl::DISP_VER_RES / 10;
|
||||
static DRAW_BUFFER: DrawBuffer<REFRESH_BUFFER_SIZE> = DrawBuffer::new();
|
||||
//
|
||||
// const NUMBER_OF_DISPLAYS: usize = 1;
|
||||
// static DISPLAY_REGISTRY: DisplayRegistry<NUMBER_OF_DISPLAYS> = DisplayRegistry::empty();
|
||||
// // static DISPLAY_REGISTRY: SingleDisplayRegistry = DisplayRegistry::empty();
|
||||
// let display = DISPLAY_REGISTRY.register_shared(&DRAW_BUFFER, shared_native_display.clone())?;
|
||||
|
||||
// Register your display update callback with LVGL. The closure you pass here will be called
|
||||
// whenever LVGL has updates to be painted to the display.
|
||||
let display = Display::register(&DRAW_BUFFER, {
|
||||
let shared_disp_inner = SyncArc::clone(&shared_native_display);
|
||||
move |update| {
|
||||
let mut em_disp = shared_disp_inner.lock();
|
||||
em_disp.draw_iter(update.as_pixels());
|
||||
}
|
||||
})?;
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = ui.scr_act()?;
|
||||
let mut screen = display.get_scr_act()?;
|
||||
|
||||
println!("Before all widgets: {:?}", mem_info());
|
||||
|
||||
let mut screen_style = Style::default();
|
||||
screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_radius(State::DEFAULT, 0);
|
||||
screen.add_style(Part::Main, screen_style)?;
|
||||
screen.add_style(Part::Main, &mut screen_style)?;
|
||||
|
||||
let mut time = Label::new(&mut screen)?;
|
||||
let mut time = Label::from("20:46");
|
||||
let mut style_time = Style::default();
|
||||
//style_time.set_text_font(font_noto_sans_numeric_28);
|
||||
// style_time.set_text_font(font_noto_sans_numeric_28);
|
||||
style_time.set_text_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
|
||||
time.add_style(Part::Main, style_time)?;
|
||||
time.add_style(Part::Main, &mut style_time)?;
|
||||
time.set_align(&mut screen, Align::Center, 0, 0)?;
|
||||
time.set_text(CString::new("20:46").unwrap().as_c_str())?;
|
||||
time.set_width(240)?;
|
||||
time.set_height(240)?;
|
||||
|
||||
let mut bt = Label::new(&mut screen)?;
|
||||
let mut bt = Label::from("#5794f2 \u{F293}#");
|
||||
bt.set_width(50)?;
|
||||
bt.set_height(80)?;
|
||||
bt.set_recolor(true)?;
|
||||
bt.set_text(CString::new("#5794f2 \u{F293}#").unwrap().as_c_str())?;
|
||||
bt.set_label_align(LabelAlign::Left)?;
|
||||
bt.set_align(&mut screen, Align::InTopLeft, 0, 0)?;
|
||||
|
||||
let mut power = Label::new(&mut screen)?;
|
||||
let mut power: Label = "#fade2a 20%#".into();
|
||||
power.set_recolor(true)?;
|
||||
power.set_width(80)?;
|
||||
power.set_height(20)?;
|
||||
power.set_text(CString::new("#fade2a 20%#").unwrap().as_c_str())?;
|
||||
power.set_label_align(LabelAlign::Right)?;
|
||||
power.set_align(&mut screen, Align::InTopRight, 0, 0)?;
|
||||
|
||||
// LVGL timer thread
|
||||
thread::spawn(|| {
|
||||
let interval = Duration::from_millis(5);
|
||||
loop {
|
||||
thread::sleep(interval);
|
||||
lvgl::tick_inc(interval);
|
||||
}
|
||||
});
|
||||
|
||||
let mut i = 0;
|
||||
let mut loop_started = Instant::now();
|
||||
'running: loop {
|
||||
if i > 59 {
|
||||
i = 0;
|
||||
|
@ -70,8 +101,11 @@ fn main() -> Result<(), LvError> {
|
|||
time.set_text(&val)?;
|
||||
i = 1 + i;
|
||||
|
||||
ui.task_handler();
|
||||
window.update(ui.get_display_ref().unwrap());
|
||||
lvgl::task_handler();
|
||||
{
|
||||
let native_display = shared_native_display.lock();
|
||||
window.update(&native_display);
|
||||
}
|
||||
|
||||
for event in window.events() {
|
||||
match event {
|
||||
|
@ -79,12 +113,12 @@ fn main() -> Result<(), LvError> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
println!("During run: {:?}", mem_info());
|
||||
sleep(Duration::from_secs(1));
|
||||
|
||||
ui.tick_inc(loop_started.elapsed());
|
||||
loop_started = Instant::now();
|
||||
}
|
||||
|
||||
println!("Final part of demo app: {:?}", mem_info());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -99,3 +133,20 @@ fn main() -> Result<(), LvError> {
|
|||
extern "C" {
|
||||
pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_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
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file lv_conf.h
|
||||
*
|
||||
* Configuration file for v7.10.1
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -80,9 +80,9 @@ typedef int16_t lv_coord_t;
|
|||
#define LV_MEM_CUSTOM 0
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
|
||||
# define LV_MEM_SIZE (1048576U) // 1Mb
|
||||
# define LV_MEM_SIZE (14U * 1024U)
|
||||
|
||||
/* Complier prefix for a big array declaration */
|
||||
/* Compiler prefix for a big array declaration */
|
||||
# define LV_MEM_ATTR
|
||||
|
||||
/* 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*/
|
||||
#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
|
||||
* Used if lvgl is binded to higher level language and the memory is managed by that language */
|
||||
#define LV_ENABLE_GC 0
|
||||
|
@ -123,14 +127,13 @@ typedef int16_t lv_coord_t;
|
|||
#define LV_INDEV_DEF_DRAG_THROW 10
|
||||
|
||||
/* 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
|
||||
|
||||
/* Repeated trigger period in long press [ms]
|
||||
* Time between `LV_EVENT_LONG_PRESSED_REPEAT */
|
||||
#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100
|
||||
|
||||
|
||||
/* Gesture threshold in pixels */
|
||||
#define LV_INDEV_DEF_GESTURE_LIMIT 50
|
||||
|
||||
|
@ -150,7 +153,7 @@ typedef void * lv_anim_user_data_t;
|
|||
|
||||
#endif
|
||||
|
||||
/* 1: Enable shadow drawing*/
|
||||
/* 1: Enable shadow drawing on rectangles*/
|
||||
#define LV_USE_SHADOW 1
|
||||
#if LV_USE_SHADOW
|
||||
/* Allow buffering some shadow calculation
|
||||
|
@ -160,6 +163,15 @@ typedef void * lv_anim_user_data_t;
|
|||
#define LV_SHADOW_CACHE_SIZE 0
|
||||
#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_...`)*/
|
||||
#define LV_USE_BLEND_MODES 1
|
||||
|
||||
|
@ -178,6 +190,22 @@ typedef void * lv_group_user_data_t;
|
|||
/* 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_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 */
|
||||
#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 */
|
||||
#define LV_USE_API_EXTENSION_V6 1
|
||||
#define LV_USE_API_EXTENSION_V7 1
|
||||
|
||||
/*========================
|
||||
* Image decoder and cache
|
||||
|
@ -210,7 +239,7 @@ typedef void * lv_fs_drv_user_data_t;
|
|||
* (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.
|
||||
* 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
|
||||
|
||||
/*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
|
||||
*====================*/
|
||||
|
||||
/* For big endian systems set to 1 */
|
||||
#define LV_BIG_ENDIAN_SYSTEM 0
|
||||
|
||||
/* Define a custom attribute to `lv_tick_inc` function */
|
||||
#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 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
|
||||
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed.
|
||||
* E.g. __attribute__((aligned(4))) */
|
||||
* 4 or 8 byte boundary. Some HW may need even 32 or 64 bytes.
|
||||
* 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
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
*==================*/
|
||||
|
@ -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`) */
|
||||
#define LV_TICK_CUSTOM 0
|
||||
#if LV_TICK_CUSTOM == 1
|
||||
#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/
|
||||
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/
|
||||
#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 system time in ms*/
|
||||
#endif /*LV_TICK_CUSTOM*/
|
||||
|
||||
typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/
|
||||
|
@ -330,15 +372,17 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
|
|||
|
||||
/* The built-in fonts contains the ASCII range and some Symbols with 4 bit-per-pixel.
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Montserrat fonts with bpp = 4
|
||||
* 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_14 0
|
||||
#define LV_FONT_MONTSERRAT_16 1
|
||||
#define LV_FONT_MONTSERRAT_14 1
|
||||
#define LV_FONT_MONTSERRAT_16 0
|
||||
#define LV_FONT_MONTSERRAT_18 0
|
||||
#define LV_FONT_MONTSERRAT_20 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
|
||||
* http://pelulamu.net/unscii/ */
|
||||
#define LV_FONT_UNSCII_8 0
|
||||
#define LV_FONT_UNSCII_16 0
|
||||
|
||||
/* Optionally declare your custom fonts here.
|
||||
* 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.*/
|
||||
#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.
|
||||
* Important only if "subpx fonts" are used.
|
||||
* With "normal" font it doesn't matter.
|
||||
*/
|
||||
#define LV_FONT_SUBPX_BGR 0
|
||||
#endif
|
||||
|
||||
/*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/
|
||||
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 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
|
||||
* 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.
|
||||
* Flags:
|
||||
* LV_THEME_MATERIAL_FLAG_LIGHT: light theme
|
||||
* LV_THEME_MATERIAL_FLAG_DARK: dark theme*/
|
||||
#define LV_USE_THEME_MATERIAL 1
|
||||
* LV_THEME_MATERIAL_FLAG_DARK: dark theme
|
||||
* 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.
|
||||
* If LV_THEME_DEFAULT_COLOR_PRIMARY is LV_COLOR_BLACK the
|
||||
* texts and borders will be black and the background will be
|
||||
* white. Else the colors are inverted.
|
||||
* 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_INIT lv_theme_material_init
|
||||
#define LV_THEME_DEFAULT_COLOR_PRIMARY LV_COLOR_RED
|
||||
#define LV_THEME_DEFAULT_COLOR_SECONDARY LV_COLOR_BLUE
|
||||
#define LV_THEME_DEFAULT_COLOR_PRIMARY lv_color_hex(0x01a2b1)
|
||||
#define LV_THEME_DEFAULT_COLOR_SECONDARY lv_color_hex(0x44d1b6)
|
||||
#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_NORMAL &lv_font_montserrat_16
|
||||
#define LV_THEME_DEFAULT_FONT_SUBTITLE &lv_font_montserrat_16
|
||||
#define LV_THEME_DEFAULT_FONT_TITLE &lv_font_montserrat_16
|
||||
#define LV_THEME_DEFAULT_FONT_SMALL &lv_font_montserrat_14
|
||||
#define LV_THEME_DEFAULT_FONT_NORMAL &lv_font_montserrat_14
|
||||
#define LV_THEME_DEFAULT_FONT_SUBTITLE &lv_font_montserrat_14
|
||||
#define LV_THEME_DEFAULT_FONT_TITLE &lv_font_montserrat_14
|
||||
|
||||
/*=================
|
||||
* Text settings
|
||||
|
@ -456,7 +513,7 @@ typedef void * lv_font_user_data_t;
|
|||
|
||||
/* Support bidirectional 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*/
|
||||
#define LV_USE_BIDI 0
|
||||
#if LV_USE_BIDI
|
||||
|
@ -498,7 +555,7 @@ typedef void * lv_obj_user_data_t;
|
|||
#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
|
||||
|
||||
/* Enable to make the object clickable on a larger area.
|
||||
|
@ -529,6 +586,9 @@ typedef void * lv_obj_user_data_t;
|
|||
|
||||
/*Calendar (dependencies: -)*/
|
||||
#define LV_USE_CALENDAR 1
|
||||
#if LV_USE_CALENDAR
|
||||
# define LV_CALENDAR_WEEK_STARTS_MONDAY 0
|
||||
#endif
|
||||
|
||||
/*Canvas (dependencies: lv_img)*/
|
||||
#define LV_USE_CANVAS 1
|
||||
|
@ -613,7 +673,7 @@ typedef void * lv_obj_user_data_t;
|
|||
* 1: Some extra precision
|
||||
* 2: Best precision
|
||||
*/
|
||||
# define LV_LINEMETER_PRECISE 0
|
||||
# define LV_LINEMETER_PRECISE 1
|
||||
#endif
|
||||
|
||||
/*Mask (dependencies: -)*/
|
||||
|
@ -667,6 +727,7 @@ typedef void * lv_obj_user_data_t;
|
|||
#define LV_USE_TABLE 1
|
||||
#if LV_USE_TABLE
|
||||
# define LV_TABLE_COL_MAX 12
|
||||
# define LV_TABLE_CELL_STYLE_CNT 4
|
||||
#endif
|
||||
|
||||
/*Tab (dependencies: lv_page, lv_btnm)*/
|
||||
|
|
66
lvgl-codegen/src/analysis.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
/// A parameter of C functions.
|
||||
///
|
||||
/// This struct represents all relevant information we can extract from the C function declaration
|
||||
/// of a LVGL public interface. We can use this information to do inference for how the parameter
|
||||
/// should be represented in a safe Rust API.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CParameter {
|
||||
/// The name of the parameter in the C code.
|
||||
pub name: String,
|
||||
|
||||
/// This is the raw representation of the Rust equivalent of the C type.
|
||||
pub c_type: String,
|
||||
|
||||
/// Takes a pointer to a type that is referenced by the LVGL code permanently.
|
||||
pub scope: ParameterScope,
|
||||
|
||||
/// The pointer is not marked as `*const` so the referenced object can be mutated.
|
||||
pub mutable: bool,
|
||||
|
||||
/// We need to check if the value is optional in the C code. We need to check
|
||||
/// the function comments for this information.
|
||||
/// - "if NULL then"
|
||||
/// - "if not NULL then"
|
||||
/// - "NULL to"
|
||||
pub allow_none: bool,
|
||||
|
||||
/// Comment associated with the parameter, if exists.
|
||||
pub comment: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ParameterScope {
|
||||
Call,
|
||||
Static,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum FunctionKind {
|
||||
Constructor,
|
||||
Method,
|
||||
Function,
|
||||
}
|
||||
|
||||
/// Inference from a LVGL C API function.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Function {
|
||||
/// Name of the function in the LVGL C API.
|
||||
pub name: String,
|
||||
|
||||
/// Comment associated with the function, if exists.
|
||||
pub comment: Option<String>,
|
||||
|
||||
pub kind: FunctionKind,
|
||||
|
||||
pub parameters: Vec<CParameter>,
|
||||
|
||||
pub ret: Return,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Return {
|
||||
Value(Option<CParameter>),
|
||||
|
||||
/// If the return is a LVGL result
|
||||
ResultError(CParameter),
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
mod analysis;
|
||||
|
||||
use inflector::cases::pascalcase::to_pascal_case;
|
||||
use lazy_static::lazy_static;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
|
@ -44,6 +46,12 @@ pub struct LvWidget {
|
|||
methods: Vec<LvFunc>,
|
||||
}
|
||||
|
||||
impl LvWidget {
|
||||
fn pascal_name(&self) -> String {
|
||||
to_pascal_case(&self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rusty for LvWidget {
|
||||
type Parent = ();
|
||||
|
||||
|
@ -53,7 +61,7 @@ impl Rusty for LvWidget {
|
|||
return Err(WrapperError::Skip);
|
||||
}
|
||||
|
||||
let widget_name = format_ident!("{}", to_pascal_case(self.name.as_str()));
|
||||
let widget_name = format_ident!("{}", self.pascal_name());
|
||||
let methods: Vec<TokenStream> = self.methods.iter().flat_map(|m| m.code(self)).collect();
|
||||
Ok(quote! {
|
||||
define_object!(#widget_name);
|
||||
|
@ -90,6 +98,7 @@ impl Rusty for LvFunc {
|
|||
type Parent = LvWidget;
|
||||
|
||||
fn code(&self, parent: &Self::Parent) -> WrapperResult<TokenStream> {
|
||||
let widget_name = format_ident!("{}", parent.pascal_name());
|
||||
let templ = format!("{}{}_", LIB_PREFIX, parent.name.as_str());
|
||||
let new_name = self.name.replace(templ.as_str(), "");
|
||||
let func_name = format_ident!("{}", new_name);
|
||||
|
@ -99,12 +108,12 @@ impl Rusty for LvFunc {
|
|||
if new_name.as_str().eq("create") {
|
||||
return Ok(quote! {
|
||||
|
||||
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
|
||||
where
|
||||
C: crate::NativeObject,
|
||||
{
|
||||
pub fn create(parent: &mut impl crate::NativeObject, copy: Option<&#widget_name>) -> crate::LvResult<Self> {
|
||||
unsafe {
|
||||
let ptr = lvgl_sys::#original_func_name(parent.raw()?.as_mut(), core::ptr::null_mut());
|
||||
let ptr = lvgl_sys::#original_func_name(
|
||||
parent.raw()?.as_mut(),
|
||||
copy.map(|c| c.raw().unwrap().as_mut() as *mut lvgl_sys::lv_obj_t).unwrap_or(core::ptr::null_mut() as *mut lvgl_sys::lv_obj_t),
|
||||
);
|
||||
if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
||||
let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
||||
Ok(Self { core })
|
||||
|
@ -114,6 +123,15 @@ impl Rusty for LvFunc {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_at(parent: &mut impl crate::NativeObject) -> crate::LvResult<Self> {
|
||||
Ok(Self::create(parent, None)?)
|
||||
}
|
||||
|
||||
pub fn new() -> crate::LvResult<Self> {
|
||||
let mut parent = crate::display::DefaultDisplay::get_scr_act()?;
|
||||
Ok(Self::create_at(&mut parent)?)
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -338,6 +356,9 @@ impl Rusty for LvType {
|
|||
Some(name) => {
|
||||
let val = if self.is_str() {
|
||||
quote!(&cstr_core::CStr)
|
||||
} else if self.literal_name.contains("lv_") {
|
||||
let ident = format_ident!("{}", name);
|
||||
quote!(&#ident)
|
||||
} else {
|
||||
let ident = format_ident!("{}", name);
|
||||
quote!(#ident)
|
||||
|
@ -631,13 +652,12 @@ mod test {
|
|||
define_object!(Arc);
|
||||
|
||||
impl Arc {
|
||||
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
|
||||
where
|
||||
C: crate::NativeObject,
|
||||
{
|
||||
|
||||
pub fn create(parent: &mut impl crate::NativeObject, copy: Option<&Arc>) -> crate::LvResult<Self> {
|
||||
unsafe {
|
||||
let ptr = lvgl_sys::lv_arc_create(parent.raw()?.as_mut(), core::ptr::null_mut());
|
||||
let ptr = lvgl_sys::lv_arc_create(
|
||||
parent.raw()?.as_mut(),
|
||||
copy.map(|c| c.raw().unwrap().as_mut() as *mut lvgl_sys::lv_obj_t).unwrap_or(core::ptr::null_mut() as *mut lvgl_sys::lv_obj_t),
|
||||
);
|
||||
if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
||||
let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
||||
Ok(Self { core })
|
||||
|
@ -646,6 +666,15 @@ mod test {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_at(parent: &mut impl crate::NativeObject) -> crate::LvResult<Self> {
|
||||
Ok(Self::create(parent, None)?)
|
||||
}
|
||||
|
||||
pub fn new() -> crate::LvResult<Self> {
|
||||
let mut parent = crate::display::DefaultDisplay::get_scr_act()?;
|
||||
Ok(Self::create_at(&mut parent)?)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ fn main() {
|
|||
let bindings = bindgen::Builder::default()
|
||||
.header(shims_dir.join("lvgl_sys.h").to_str().unwrap())
|
||||
.generate_comments(false)
|
||||
.derive_default(true)
|
||||
Extremely useful feature of Extremely useful feature of `bindgen`. 💅🏽
|
||||
.layout_tests(false)
|
||||
.use_core()
|
||||
.rustfmt_bindings(true)
|
||||
|
|
|
@ -14,11 +14,14 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
lvgl-sys = { version = "0.5.2", path = "../lvgl-sys" }
|
||||
cty = "0.2.1"
|
||||
embedded-graphics = "0.6.2"
|
||||
cstr_core = "0.2.3"
|
||||
bitflags = "1.2.1"
|
||||
parking_lot = "0.11.1"
|
||||
embedded-graphics = { version = "0.6.2", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
embedded_graphics = ["embedded-graphics"]
|
||||
alloc = ["cstr_core/alloc"]
|
||||
lvgl_alloc = ["alloc"]
|
||||
|
||||
|
@ -30,28 +33,33 @@ lvgl-sys = { version = "0.5.2", path = "../lvgl-sys" }
|
|||
|
||||
[dev-dependencies]
|
||||
embedded-graphics-simulator = "0.2.1"
|
||||
heapless = "0.5.5"
|
||||
|
||||
[[example]]
|
||||
name = "app"
|
||||
path = "../examples/app.rs"
|
||||
required-features = ["alloc", "embedded_graphics"]
|
||||
|
||||
[[example]]
|
||||
name = "demo"
|
||||
path = "../examples/demo.rs"
|
||||
required-features = ["alloc"]
|
||||
required-features = ["alloc", "embedded_graphics"]
|
||||
|
||||
[[example]]
|
||||
name = "bar"
|
||||
path = "../examples/bar.rs"
|
||||
required-features = ["alloc"]
|
||||
required-features = ["alloc", "embedded_graphics"]
|
||||
|
||||
[[example]]
|
||||
name = "button_click"
|
||||
path = "../examples/button_click.rs"
|
||||
required-features = ["alloc"]
|
||||
required-features = ["alloc", "embedded_graphics"]
|
||||
|
||||
[[example]]
|
||||
name = "gauge"
|
||||
path = "../examples/gauge.rs"
|
||||
required-features = ["alloc", "embedded_graphics"]
|
||||
|
||||
[[example]]
|
||||
name = "arc"
|
||||
path = "../examples/arc.rs"
|
||||
required-features = ["lvgl_alloc"]
|
||||
required-features = ["alloc", "embedded_graphics"]
|
||||
|
|
|
@ -9,12 +9,12 @@ pub struct LvglAlloc;
|
|||
unsafe impl GlobalAlloc for LvglAlloc {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
// 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
268
lvgl/src/display.rs
Normal file
|
@ -0,0 +1,268 @@
|
|||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use crate::functions::CoreError;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use crate::{disp_drv_register, disp_get_default, get_str_act};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use crate::{Box, RunOnce};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use crate::{Color, Obj};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use core::cell::RefCell;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use core::mem::MaybeUninit;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use core::ptr::NonNull;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use core::{ptr, result};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use parking_lot::const_mutex;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use parking_lot::Mutex;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub const DISP_HOR_RES: usize = lvgl_sys::LV_HOR_RES_MAX as usize;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub const DISP_VER_RES: usize = lvgl_sys::LV_VER_RES_MAX as usize;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub enum DisplayError {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
NotAvailable,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
FailedToRegister,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
NotRegistered,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
type Result<T> = result::Result<T, DisplayError>;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub struct Display {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub(crate) disp: NonNull<lvgl_sys::lv_disp_t>,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl Display {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub(crate) fn from_raw(disp: NonNull<lvgl_sys::lv_disp_t>) -> Self {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Self { disp }
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub fn register<F, const N: usize>(
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
draw_buffer: &'static DrawBuffer<N>,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
display_update: F,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
) -> Result<Self>
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
where
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
F: FnMut(&DisplayRefresh<N>) + 'static,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
{
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let mut display_diver = DisplayDriver::new(draw_buffer, display_update)?;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Ok(disp_drv_register(&mut display_diver)?)
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub fn get_scr_act(&self) -> Result<Obj> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Ok(get_str_act(Some(&self))?)
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl Default for Display {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
fn default() -> Self {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
disp_get_default().expect("LVGL must be INITIALIZED")
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[derive(Copy, Clone)]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub struct DefaultDisplay {}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl DefaultDisplay {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
/// Gets the screen active of the default display.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub fn get_scr_act() -> Result<Obj> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Ok(get_str_act(None)?)
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub struct DrawBuffer<const N: usize> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
initialized: RunOnce,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
refresh_buffer: Mutex<RefCell<[MaybeUninit<lvgl_sys::lv_color_t>; N]>>,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
I'm using a Mutex here just to make this I'm using a Mutex here just to make this `Sync`, not sure if there is a way to remove it but still keep the memory statically allocated.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl<const N: usize> DrawBuffer<N> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub const fn new() -> Self {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Self {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
initialized: RunOnce::new(),
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
refresh_buffer: const_mutex(RefCell::new([MaybeUninit::uninit(); N])),
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
fn get_ptr(&self) -> Option<Box<lvgl_sys::lv_disp_buf_t>> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
if self.initialized.swap_and_check() {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// TODO: needs to be 'static somehow
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// Cannot be in the DrawBuffer struct because the type `lv_disp_buf_t` contains a raw
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// pointer and raw pointers are not Send and consequently cannot be in `static` variables.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let mut inner: MaybeUninit<lvgl_sys::lv_disp_buf_t> = MaybeUninit::uninit();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
I would like to find a way to make this memory statically allocated. This seems to be a requirement for LVGL v8. I would like to find a way to make this memory statically allocated. This seems to be [a requirement for LVGL v8](https://docs.lvgl.io/8.0/get-started/quick-overview.html#add-lvgl-into-your-project).
|
||||
let primary_buffer_guard = self.refresh_buffer.lock();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let draw_buf = unsafe {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
lvgl_sys::lv_disp_buf_init(
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
inner.as_mut_ptr(),
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
primary_buffer_guard.borrow_mut().as_mut_ptr() as *mut _ as *mut cty::c_void,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
ptr::null_mut(),
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
N as u32,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
inner.assume_init()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Some(Box::new(draw_buf))
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
} else {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
None
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub struct DisplayDriver {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub(crate) disp_drv: lvgl_sys::lv_disp_drv_t,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl DisplayDriver {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub fn new<F, const N: usize>(
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
draw_buffer: &'static DrawBuffer<N>,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
display_update_callback: F,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
) -> Result<Self>
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
where
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
F: FnMut(&DisplayRefresh<N>) + 'static,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
{
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let mut disp_drv = unsafe {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let mut inner = MaybeUninit::uninit();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
lvgl_sys::lv_disp_drv_init(inner.as_mut_ptr());
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
inner.assume_init()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// Safety: The variable `draw_buffer` is statically allocated, no need to worry about this being dropped.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
disp_drv.buffer = draw_buffer
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.get_ptr()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.map(|ptr| Box::into_raw(ptr) as *mut _)
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.ok_or(DisplayError::FailedToRegister)?;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
disp_drv.user_data = Box::into_raw(Box::new(display_update_callback)) as *mut _
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
as lvgl_sys::lv_disp_drv_user_data_t;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// Sets trampoline pointer to the function implementation that uses the `F` type for a
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// refresh buffer of size N specifically.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
disp_drv.flush_cb = Some(disp_flush_trampoline::<F, N>);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// We do not store any memory that can be accidentally deallocated by on the Rust side.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Ok(Self { disp_drv })
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
/// Represents a sub-area of the display that is being updated.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub struct Area {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub x1: i16,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub x2: i16,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub y1: i16,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub y2: i16,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
/// It's a update to the display information, contains the area that is being updated and the color
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
/// of the pixels that need to be updated. The colors are represented in a contiguous array.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub struct DisplayRefresh<const N: usize> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub area: Area,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub colors: [Color; N],
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[cfg(feature = "embedded_graphics")]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
mod embedded_graphics_impl {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use crate::{Color, DisplayRefresh};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use embedded_graphics::drawable;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use embedded_graphics::prelude::*;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl<const N: usize> DisplayRefresh<N> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
pub fn as_pixels<C>(&self) -> impl IntoIterator<Item = drawable::Pixel<C>> + '_
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
where
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
C: PixelColor + From<Color>,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
{
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let area = &self.area;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let x1 = area.x1;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let x2 = area.x2;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let y1 = area.y1;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let y2 = area.y2;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let ys = y1..=y2;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let xs = (x1..=x2).enumerate();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let x_len = (x2 - x1 + 1) as usize;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// We use iterators here to ensure that the Rust compiler can apply all possible
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// optimizations at compile time.
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
ys.enumerate()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.map(move |(iy, y)| {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
xs.clone().map(move |(ix, x)| {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let color_len = x_len * iy + ix;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let raw_color = self.colors[color_len];
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
drawable::Pixel(Point::new(x as i32, y as i32), raw_color.into())
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
})
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
})
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.flatten()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
unsafe extern "C" fn disp_flush_trampoline<F, const N: usize>(
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
disp_drv: *mut lvgl_sys::lv_disp_drv_t,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
area: *const lvgl_sys::lv_area_t,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
color_p: *mut lvgl_sys::lv_color_t,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
) where
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
F: FnMut(&DisplayRefresh<N>) + 'static,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
{
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let display_driver = *disp_drv;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
if !display_driver.user_data.is_null() {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let callback = &mut *(display_driver.user_data as *mut F);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let mut colors = [Color::default(); N];
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let mut color_len = 0;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
for color in &mut colors {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let lv_color = *color_p.add(color_len);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
*color = Color::from_raw(lv_color);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
color_len += 1;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let update = DisplayRefresh {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
area: Area {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
x1: (*area).x1,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
x2: (*area).x2,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
y1: (*area).y1,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
y2: (*area).y2,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
},
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
colors,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
};
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
callback(&update);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
// Indicate to LVGL that we are ready with the flushing
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
lvgl_sys::lv_disp_flush_ready(disp_drv);
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
impl From<CoreError> for DisplayError {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
fn from(err: CoreError) -> Self {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use DisplayError::*;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
match err {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
CoreError::ResourceNotAvailable => NotAvailable,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
CoreError::OperationFailed => NotAvailable,
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[cfg(test)]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
mod tests {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use super::*;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
use crate::tests;
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[test]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
fn get_scr_act_return_display() {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
tests::initialize_test();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let _screen = get_str_act(None).expect("We can get the active screen");
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[test]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
fn get_default_display() {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
tests::initialize_test();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let display = Display::default();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let _screen_direct = display
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.get_scr_act()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.expect("Return screen directly from the display instance");
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let _screen_default =
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
DefaultDisplay::get_scr_act().expect("Return screen from the default display");
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
#[test]
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
fn register_display_directly() -> Result<()> {
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
tests::initialize_test();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let display = Display::default();
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
let _screen = display
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.get_scr_act()
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
.expect("Return screen directly from the display instance");
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
Ok(())
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
||||
}
|
||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
56
lvgl/src/functions.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use crate::display::{Display, DisplayDriver};
|
||||
use crate::{Obj, Widget};
|
||||
use core::ptr::NonNull;
|
||||
use core::time::Duration;
|
||||
use core::{ptr, result};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum CoreError {
|
||||
ResourceNotAvailable,
|
||||
OperationFailed,
|
||||
}
|
||||
|
||||
type Result<T> = result::Result<T, CoreError>;
|
||||
|
||||
/// Register own buffer
|
||||
pub(crate) fn disp_drv_register(disp_drv: &mut DisplayDriver) -> Result<Display> {
|
||||
let disp_ptr = unsafe { lvgl_sys::lv_disp_drv_register(&mut disp_drv.disp_drv as *mut _) };
|
||||
Ok(Display::from_raw(
|
||||
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)?,
|
||||
))
|
||||
}
|
||||
|
||||
/// You have to call this function periodically.
|
||||
/// Expects a `tick_period` duration as argument which is the call period of this
|
||||
/// function in milliseconds.
|
||||
#[inline]
|
||||
pub fn tick_inc(tick_period: Duration) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_tick_inc(tick_period.as_millis() as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Call it periodically to handle tasks.
|
||||
#[inline]
|
||||
pub fn task_handler() {
|
||||
unsafe { lvgl_sys::lv_task_handler() };
|
||||
}
|
|
@ -17,7 +17,10 @@
|
|||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
#[cfg(feature = "lvgl_alloc")]
|
||||
#[macro_use]
|
||||
mod lv_core;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
// We can ONLY use `alloc::boxed::Box` if `lvgl_alloc` is enabled.
|
||||
|
@ -31,12 +34,6 @@ use ::alloc::boxed::Box;
|
|||
#[cfg(feature = "lvgl_alloc")]
|
||||
mod allocator;
|
||||
|
||||
mod support;
|
||||
mod ui;
|
||||
#[macro_use]
|
||||
mod lv_core;
|
||||
pub mod widgets;
|
||||
|
||||
#[cfg(not(feature = "lvgl_alloc"))]
|
||||
pub(crate) mod mem;
|
||||
|
||||
|
@ -47,22 +44,54 @@ pub(crate) mod mem;
|
|||
#[cfg(not(feature = "lvgl_alloc"))]
|
||||
use crate::mem::Box;
|
||||
|
||||
mod display;
|
||||
pub use display::*;
|
||||
mod functions;
|
||||
mod support;
|
||||
pub mod widgets;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
pub use functions::*;
|
||||
pub use lv_core::*;
|
||||
pub use support::*;
|
||||
pub use ui::*;
|
||||
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
struct RunOnce(AtomicBool);
|
||||
|
||||
// Initialize LVGL only once.
|
||||
static LVGL_INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||
impl RunOnce {
|
||||
const fn new() -> Self {
|
||||
Self(AtomicBool::new(false))
|
||||
}
|
||||
|
||||
pub(crate) fn lvgl_init() {
|
||||
if LVGL_INITIALIZED
|
||||
fn swap_and_check(&self) -> bool {
|
||||
self.0
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static LVGL_INITIALIZED: RunOnce = RunOnce::new();
|
||||
|
||||
pub fn init() {
|
||||
if LVGL_INITIALIZED.swap_and_check() {
|
||||
unsafe {
|
||||
lvgl_sys::lv_init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::display::{Display, DrawBuffer};
|
||||
|
||||
pub(crate) fn initialize_test() {
|
||||
init();
|
||||
|
||||
const REFRESH_BUFFER_SIZE: usize = 64 * 64 / 10;
|
||||
static DRAW_BUFFER: DrawBuffer<REFRESH_BUFFER_SIZE> = DrawBuffer::new();
|
||||
static ONCE_INIT: RunOnce = RunOnce::new();
|
||||
|
||||
if ONCE_INIT.swap_and_check() {
|
||||
let _ = Display::register(&DRAW_BUFFER, |_| {}).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::lv_core::style::Style;
|
||||
use crate::Box;
|
||||
use crate::{Align, LvError, LvResult};
|
||||
use core::ptr;
|
||||
|
||||
|
@ -35,14 +34,15 @@ pub trait Widget: NativeObject {
|
|||
|
||||
/// Construct an instance of the object from a raw pointer.
|
||||
///
|
||||
/// # Safety
|
||||
/// 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 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: &mut 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(),
|
||||
style.raw.as_mut() as *mut _,
|
||||
);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ impl Widget for Obj {
|
|||
type SpecialEvent = ();
|
||||
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() }
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ macro_rules! define_object {
|
|||
type SpecialEvent = $event_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 {
|
||||
core: $crate::Obj::from_raw(raw_pointer),
|
||||
}
|
||||
|
@ -176,6 +176,38 @@ macro_rules! define_object {
|
|||
};
|
||||
}
|
||||
|
||||
// define_object!(Rafael);
|
||||
//
|
||||
// impl Rafael {
|
||||
// pub fn create(
|
||||
// parent: &mut impl crate::NativeObject,
|
||||
// copy: Option<&Rafael>,
|
||||
// ) -> crate::LvResult<Self> {
|
||||
// unsafe {
|
||||
// let ptr = lvgl_sys::lv_arc_create(
|
||||
// parent.raw()?.as_mut(),
|
||||
// copy.map(|c| c.raw().unwrap().as_mut() as *mut lvgl_sys::lv_obj_t)
|
||||
// .unwrap_or(core::ptr::null_mut() as *mut lvgl_sys::lv_obj_t),
|
||||
// );
|
||||
// if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
||||
// let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
||||
// Ok(Self { core })
|
||||
// } else {
|
||||
// Err(crate::LvError::InvalidReference)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn create_at(parent: &mut impl crate::NativeObject) -> crate::LvResult<Self> {
|
||||
// Ok(Self::create(parent, None)?)
|
||||
// }
|
||||
//
|
||||
// pub fn new() -> crate::LvResult<Self> {
|
||||
// let mut parent = crate::display::DefaultDisplay::get_scr_act()?;
|
||||
// Ok(Self::create_at(&mut parent)?)
|
||||
// }
|
||||
// }
|
||||
|
||||
bitflags! {
|
||||
pub struct State: u32 {
|
||||
/// Normal, released
|
||||
|
|
|
@ -11,7 +11,7 @@ pub(crate) struct Box<T>(NonNull<T>);
|
|||
|
||||
impl<T> Box<T> {
|
||||
/// 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 inner = unsafe {
|
||||
let ptr = lvgl_sys::lv_mem_alloc(size as lvgl_sys::size_t) as *mut T;
|
||||
|
@ -29,10 +29,10 @@ impl<T> Box<T> {
|
|||
p
|
||||
})
|
||||
.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 {
|
||||
|
@ -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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::mem::mem_info;
|
||||
use crate::*;
|
||||
use std::vec::Vec;
|
||||
Probably just need to make safe bindings for this simple function and add to the public API. It's useful for app debugging. Probably just need to make safe bindings for this simple function and add to the public API. It's useful for app debugging.
|
||||
|
||||
#[test]
|
||||
fn place_value_in_lv_mem() {
|
||||
crate::lvgl_init();
|
||||
tests::initialize_test();
|
||||
|
||||
let v = Box::new(5);
|
||||
drop(v);
|
||||
|
@ -86,7 +105,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn place_complex_value_in_lv_mem() {
|
||||
crate::lvgl_init();
|
||||
tests::initialize_test();
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
|
@ -135,21 +154,4 @@ mod test {
|
|||
// If this fails, we are leaking memory! BOOM! \o/
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::display::DisplayError;
|
||||
use crate::Widget;
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[cfg(feature = "embedded_graphics")]
|
||||
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
|
||||
|
||||
pub type LvResult<T> = Result<T, LvError>;
|
||||
|
@ -13,7 +16,18 @@ pub enum LvError {
|
|||
AlreadyInUse,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
impl From<DisplayError> for LvError {
|
||||
fn from(err: DisplayError) -> Self {
|
||||
use LvError::*;
|
||||
match err {
|
||||
DisplayError::NotAvailable => Uninitialized,
|
||||
DisplayError::FailedToRegister => InvalidReference,
|
||||
DisplayError::NotRegistered => Uninitialized,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct Color {
|
||||
pub(crate) raw: lvgl_sys::lv_color_t,
|
||||
}
|
||||
|
@ -41,6 +55,7 @@ impl Color {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded_graphics")]
|
||||
impl From<Color> for Rgb888 {
|
||||
fn from(color: Color) -> Self {
|
||||
unsafe {
|
||||
|
@ -53,6 +68,7 @@ impl From<Color> for Rgb888 {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded_graphics")]
|
||||
impl From<Color> for Rgb565 {
|
||||
fn from(color: Color) -> Self {
|
||||
unsafe {
|
||||
|
|
203
lvgl/src/ui.rs
|
@ -1,203 +0,0 @@
|
|||
use crate::Box;
|
||||
use crate::{Color, Event, LvError, LvResult, Obj, Widget};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::time::Duration;
|
||||
use embedded_graphics::pixelcolor::PixelColor;
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics::{drawable, DrawTarget};
|
||||
|
||||
// There can only be a single reference to LVGL library.
|
||||
static LVGL_IN_USE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
// TODO: Make this an external configuration
|
||||
const REFRESH_BUFFER_LEN: usize = 2;
|
||||
// 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 struct UI<T, C>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
// LVGL is not thread-safe by default.
|
||||
_not_sync: PhantomData<*mut ()>,
|
||||
// Later we can add possibility to have multiple displays by using `heapless::Vec`
|
||||
display_data: Option<DisplayUserData<T, C>>,
|
||||
}
|
||||
|
||||
// LVGL does not use thread locals.
|
||||
unsafe impl<T, C> Send for UI<T, C>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, C> UI<T, C>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
pub fn init() -> LvResult<Self> {
|
||||
if LVGL_IN_USE
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
crate::lvgl_init();
|
||||
Ok(Self {
|
||||
_not_sync: PhantomData,
|
||||
display_data: None,
|
||||
})
|
||||
} else {
|
||||
Err(LvError::AlreadyInUse)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disp_drv_register(&mut self, display: T) -> LvResult<()> {
|
||||
self.display_data = Some(DisplayUserData {
|
||||
display,
|
||||
phantom: PhantomData,
|
||||
});
|
||||
|
||||
let refresh_buffer1 = [Color::from_rgb((0, 0, 0)).raw; BUF_SIZE];
|
||||
let refresh_buffer2 = [Color::from_rgb((0, 0, 0)).raw; BUF_SIZE];
|
||||
|
||||
let mut disp_buf = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
|
||||
let mut disp_drv = MaybeUninit::<lvgl_sys::lv_disp_drv_t>::uninit();
|
||||
|
||||
unsafe {
|
||||
// Initialize the display buffer
|
||||
lvgl_sys::lv_disp_buf_init(
|
||||
disp_buf.as_mut_ptr(),
|
||||
Box::into_raw(Box::new(refresh_buffer1)) as *mut cty::c_void,
|
||||
Box::into_raw(Box::new(refresh_buffer2)) as *mut cty::c_void,
|
||||
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
|
||||
);
|
||||
// Basic initialization of the display driver
|
||||
lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr());
|
||||
let mut disp_drv = Box::new(disp_drv.assume_init());
|
||||
// Assign the buffer to the display
|
||||
disp_drv.buffer = Box::into_raw(Box::new(disp_buf.assume_init()));
|
||||
// Set your driver function
|
||||
disp_drv.flush_cb = Some(display_callback_wrapper::<T, C>);
|
||||
disp_drv.user_data = &mut self.display_data as *mut _ as *mut cty::c_void;
|
||||
// We need to remember to deallocate the `disp_drv` memory when dropping UI
|
||||
lvgl_sys::lv_disp_drv_register(Box::into_raw(disp_drv));
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_display_ref(&self) -> Option<&T> {
|
||||
match self.display_data.as_ref() {
|
||||
None => None,
|
||||
Some(v) => Some(&v.display),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scr_act(&self) -> LvResult<Obj> {
|
||||
unsafe {
|
||||
let screen = lvgl_sys::lv_disp_get_scr_act(ptr::null_mut());
|
||||
if let Some(v) = NonNull::new(screen) {
|
||||
Ok(Obj::from_raw(v))
|
||||
} else {
|
||||
Err(LvError::InvalidReference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_send<W>(&mut self, obj: &mut W, event: Event<W::SpecialEvent>) -> LvResult<()>
|
||||
where
|
||||
W: Widget,
|
||||
{
|
||||
unsafe {
|
||||
lvgl_sys::lv_event_send(obj.raw()?.as_mut(), event.into(), ptr::null_mut());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tick_inc(&mut self, tick_period: Duration) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_tick_inc(tick_period.as_millis() as u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn task_handler(&mut self) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_task_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DisplayUserData<T, C>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
display: T,
|
||||
phantom: PhantomData<C>,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn display_callback_wrapper<T, C>(
|
||||
disp_drv: *mut lvgl_sys::lv_disp_drv_t,
|
||||
area: *const lvgl_sys::lv_area_t,
|
||||
color_p: *mut lvgl_sys::lv_color_t,
|
||||
) where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
// In the `std` world we would make sure to capture panics here and make them not escape across
|
||||
// the FFI boundary. Since this library is focused on embedded platforms, we don't
|
||||
// have an standard unwinding mechanism to rely upon.
|
||||
let display_driver = *disp_drv;
|
||||
// Rust code closure reference
|
||||
if !display_driver.user_data.is_null() {
|
||||
let user_data = &mut *(display_driver.user_data as *mut DisplayUserData<T, C>);
|
||||
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(&mut user_data.display, (x1, x2), (y1, y2), color_p);
|
||||
}
|
||||
// Indicate to LVGL that we are ready with the flushing
|
||||
lvgl_sys::lv_disp_flush_ready(disp_drv);
|
||||
}
|
||||
|
||||
// We separate this display flush function to reduce the amount of unsafe code we need to write.
|
||||
// This also provides a good separation of concerns, what is necessary from LVGL to work and
|
||||
// what is the lvgl-rs wrapper responsibility.
|
||||
fn display_flush<T, C>(
|
||||
display: &mut T,
|
||||
(x1, x2): (i16, i16),
|
||||
(y1, y2): (i16, i16),
|
||||
color_p: *mut lvgl_sys::lv_color_t,
|
||||
) -> Result<(), T::Error>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
let ys = y1..=y2;
|
||||
let xs = (x1..=x2).enumerate();
|
||||
let x_len = (x2 - x1 + 1) as usize;
|
||||
|
||||
// We use iterators here to ensure that the Rust compiler can apply all possible
|
||||
// optimizations at compile time.
|
||||
let pixels = ys
|
||||
.enumerate()
|
||||
.map(|(iy, y)| {
|
||||
xs.clone().map(move |(ix, x)| {
|
||||
let color_len = x_len * iy + ix;
|
||||
let lv_color = unsafe { *color_p.add(color_len) };
|
||||
let raw_color = Color::from_raw(lv_color);
|
||||
drawable::Pixel(Point::new(x as i32, y as i32), raw_color.into())
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
|
||||
Ok(display.draw_iter(pixels)?)
|
||||
}
|
|
@ -10,6 +10,37 @@ impl Label {
|
|||
}
|
||||
}
|
||||
|
||||
This is a test of what is possible with This is a test of what is possible with `alloc` feature enabled. In reality, the `From` trait implementation should use the `TryFrom` trait implementation and just call `.unwrap()` here. People will decide which guarantees they want to have.
|
||||
#[cfg(feature = "alloc")]
|
||||
mod alloc_imp {
|
||||
use crate::widgets::Label;
|
||||
use crate::LvError;
|
||||
use cstr_core::CString;
|
||||
use core::convert::TryFrom;
|
||||
|
||||
impl<S: AsRef<str>> From<S> for Label {
|
||||
fn from(text: S) -> Self {
|
||||
// text.try_into().unwrap()
|
||||
let text_cstr = CString::new(text.as_ref()).unwrap();
|
||||
let mut label = Label::new().unwrap();
|
||||
label.set_text(text_cstr.as_c_str()).unwrap();
|
||||
label
|
||||
}
|
||||
}
|
||||
|
||||
// Issue link: https://github.com/rust-lang/rust/issues/50133
|
||||
//
|
||||
// impl<S: AsRef<str>> TryFrom<S> for Label {
|
||||
// type Error = LvError;
|
||||
// fn try_from(text: S) -> Result<Self, Self::Error> {
|
||||
// let text_cstr = CString::new(text.as_ref())?;
|
||||
// let mut label = Label::new()?;
|
||||
// label.set_text(text_cstr.as_c_str())?;
|
||||
// Ok(label)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum LabelAlign {
|
||||
|
|
Making this statically allocated will avoid dropping this memory address by mistake in an app code.