Integrate embeddedgraphics #2

Merged
rafaelcaricio merged 4 commits from integrate_embeddedgraphics into master 2020-04-19 13:40:04 +00:00
4 changed files with 26 additions and 166 deletions
Showing only changes of commit 2cd2f1da87 - Show all commits

View file

@ -10,4 +10,5 @@ publish = false
[dependencies]
lvgl = { path = "../../lvgl" }
lvgl-sys = { path = "../../lvgl-sys" }
sdl2 = "0.33.0"
embedded-graphics = "0.6"
embedded-graphics-simulator = "0.2.0"

View file

@ -1,68 +1,30 @@
use lvgl;
use lvgl::Object;
use lvgl_sys;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::rect::Point;
use std::mem::MaybeUninit;
use std::os::raw::c_void;
use std::panic;
use std::time::Duration;
use embedded_graphics::pixelcolor::Rgb888;
use embedded_graphics::mock_display::MockDisplay;
use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window, BinaryColorTheme, SimulatorEvent};
fn main() -> Result<(), String> {
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let mut framebuffer = [[Color::from((0, 0, 0)); lvgl_sys::LV_VER_RES_MAX as usize];
lvgl_sys::LV_HOR_RES_MAX as usize];
let mut display: SimulatorDisplay<Rgb888> = SimulatorDisplay::new(Size::new(lvgl_sys::LV_HOR_RES_MAX,lvgl_sys::LV_VER_RES_MAX));
let window = video_subsystem
.window(
"TFT Display: Demo",
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
)
.position_centered()
.opengl()
.build()
.map_err(|e| e.to_string())?;
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.clear();
canvas.present();
let output_settings = OutputSettingsBuilder::new()
.theme(BinaryColorTheme::OledBlue)
.build();
let mut window = Window::new("Hello World", &output_settings);
unsafe {
lvgl_sys::lv_init();
}
// Implement and register a function which can copy a pixel array to an area of your display:
let mut display_driver = DisplayDriver::new(move |points, colors| {
for (i, point) in points.into_iter().enumerate() {
let color = &mut framebuffer[point.x() as usize][point.y() as usize];
*color = colors[i].clone();
}
canvas.clear();
for (x, line) in framebuffer.iter().enumerate() {
for (y, color) in line.iter().enumerate() {
canvas.set_draw_color(color.clone());
canvas.draw_point(Point::new(x as i32, y as i32)).unwrap();
}
}
canvas.present();
});
// Implement and register your display:
let mut display_driver = lvgl::DisplayDriver::new(&mut display);
// Create screen and widgets
let mut screen = display_driver.get_active_screen();
// let mut button = lvgl::Button::new(&mut screen);
// button.set_pos(50, 50);
// button.set_size(100, 50);
//
// let mut label = lvgl::Label::new(&mut button);
// label.set_text("Hello Mundo!\0");
let font_roboto_28 = unsafe { &lvgl_sys::lv_font_roboto_28 };
let font_noto_sans_numeric_28 = unsafe { &noto_sans_numeric_80 };
@ -102,22 +64,9 @@ fn main() -> Result<(), String> {
power.set_label_align(lvgl::LabelAlign::Right);
power.set_align(&mut screen, lvgl::Align::InTopRight, 0, 0);
let mut event_pump = sdl_context.event_pump()?;
let mut i = 0;
'running: loop {
if let Some(event) = event_pump.poll_event() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => {
break 'running;
}
_ => {}
}
}
if i > 59 {
i = 0;
}
@ -130,6 +79,14 @@ fn main() -> Result<(), String> {
lvgl_sys::lv_task_handler();
lvgl_sys::lv_tick_inc(10);
}
window.update(&display);
for event in window.events() {
match event {
SimulatorEvent::Quit => break 'running,
_ => {}
}
}
}
Ok(())
@ -139,102 +96,3 @@ fn main() -> Result<(), String> {
extern "C" {
pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_t;
}
#[allow(dead_code)]
struct DisplayDriver<F>
where
F: FnMut(Vec<Point>, Vec<Color>),
{
pub raw: lvgl_sys::lv_disp_drv_t,
callback: F,
display_buffer: MaybeUninit<lvgl_sys::lv_disp_buf_t>,
refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>; lvgl_sys::LV_HOR_RES_MAX as usize * 10],
}
impl<F> DisplayDriver<F>
where
F: FnMut(Vec<Point>, Vec<Color>),
{
fn new(mut callback: F) -> Self {
// Create a display buffer for LittlevGL
let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
let mut refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>;
lvgl_sys::LV_HOR_RES_MAX as usize * 10] =
unsafe { MaybeUninit::uninit().assume_init() }; /*Declare a buffer for 10 lines*/
unsafe {
// Initialize the display buffer
lvgl_sys::lv_disp_buf_init(
display_buffer.as_mut_ptr(),
refresh_buffer.as_mut_ptr() as *mut c_void,
std::ptr::null_mut(),
(lvgl_sys::LV_HOR_RES_MAX * 10) as u32,
);
}
let mut disp_drv = unsafe {
let mut disp_drv = MaybeUninit::<lvgl_sys::lv_disp_drv_t>::uninit().assume_init(); /*Descriptor of a display driver*/
lvgl_sys::lv_disp_drv_init(&mut disp_drv); // Basic initialization
disp_drv.flush_cb = Some(display_callback_wrapper::<F>); // Set your driver function
disp_drv.user_data = &mut callback as *mut _ as *mut c_void;
disp_drv
};
disp_drv.buffer = display_buffer.as_mut_ptr(); // Assign the buffer to the display
unsafe {
lvgl_sys::lv_disp_drv_register(&mut disp_drv); // Finally register the driver
}
Self {
raw: disp_drv,
callback,
display_buffer,
refresh_buffer,
}
}
fn get_active_screen(&mut self) -> lvgl::ObjectX<'static> {
lvgl::display::get_active_screen()
}
}
unsafe extern "C" fn display_callback_wrapper<F>(
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
F: FnMut(Vec<Point>, Vec<Color>),
{
// We need to make sure panics can't escape across the FFI boundary.
let _ = panic::catch_unwind(|| {
let mut i = 0;
let disp = *disp_drv;
// Rust code closure reference
let closure = &mut *(disp.user_data as *mut F);
let mut points = vec![];
let mut colors = vec![];
for y in (*area).y1..=(*area).y2 {
for x in (*area).x1..=(*area).x2 {
// Convert point to paint to a high-level Rust repr
points.push(Point::new(x as i32, y as i32));
// Convert C color representation to high-level Rust
let raw_color = *color_p.add(i);
let color = Color::from((
raw_color.ch.red,
raw_color.ch.green,
raw_color.ch.blue,
raw_color.ch.alpha,
));
colors.push(color);
i = i + 1;
}
}
// Callback the Rust closure to flush the new points to the screen
closure(points, colors);
// Indicate to LittlevGL that you are ready with the flushing
lvgl_sys::lv_disp_flush_ready(disp_drv);
});
}

View file

@ -8,11 +8,11 @@ use embedded_graphics::pixelcolor::Rgb888;
use core::marker::PhantomData;
struct DisplayDriver<'a, T>
pub struct DisplayDriver<'a, T>
where
T: DrawTarget<Rgb888>,
rafaelcaricio commented 2020-04-19 13:31:49 +00:00 (Migrated from github.com)
Review

Would be nice to have this type more generic. Not all embedded systems will support that.

Would be nice to have this type more generic. Not all embedded systems will support that.
{
pub raw: lvgl_sys::lv_disp_drv_t,
raw: lvgl_sys::lv_disp_drv_t,
display_buffer: MaybeUninit<lvgl_sys::lv_disp_buf_t>,
refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>; lvgl_sys::LV_HOR_RES_MAX as usize * 10],
phantom: &'a PhantomData<T>,
@ -61,7 +61,7 @@ impl<'a, T> DisplayDriver<'a, T> where
}
}
fn get_active_screen(&mut self) -> ObjectX<'static> {
pub fn get_active_screen(&mut self) -> ObjectX<'static> {
get_active_screen()
}
}

View file

@ -3,4 +3,5 @@
pub mod display;
mod objx;
pub use display::DisplayDriver;
pub use objx::*;