Integrate embeddedgraphics #2

Merged
rafaelcaricio merged 4 commits from integrate_embeddedgraphics into master 2020-04-19 13:40:04 +00:00
5 changed files with 121 additions and 165 deletions

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

@ -13,5 +13,6 @@ keywords = ["littlevgl", "lvgl", "graphical_interfaces"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lvgl-sys = {path="../lvgl-sys", version="0.1.1"}
cty = "0.2.1"
lvgl-sys = {path="../lvgl-sys", version="0.1"}
cty = "0.2"
embedded-graphics = "0.6"

View file

@ -1,5 +1,100 @@
use crate::objx::ObjectX;
use core::ptr;
use embedded_graphics;
use embedded_graphics::prelude::*;
use embedded_graphics::{drawable, DrawTarget};
use core::mem::MaybeUninit;
use embedded_graphics::pixelcolor::Rgb888;
use core::marker::PhantomData;
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.
{
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>,
}
impl<'a, T> DisplayDriver<'a, T> where
T: DrawTarget<Rgb888>
{
pub fn new(device: &'a mut T) -> Self {
// Create a display buffer for LittlevGL
let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
// Declare a buffer for 10 lines
let mut refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>;
lvgl_sys::LV_HOR_RES_MAX as usize * 10] =
unsafe { MaybeUninit::uninit().assume_init() };
// Initialize the display buffer
unsafe {
lvgl_sys::lv_disp_buf_init(
display_buffer.as_mut_ptr(),
refresh_buffer.as_mut_ptr() as *mut cty::c_void,
core::ptr::null_mut(),
(lvgl_sys::LV_HOR_RES_MAX * 10) as u32,
);
}
let mut disp_drv = unsafe {
// Descriptor of a display driver
let mut disp_drv = MaybeUninit::<lvgl_sys::lv_disp_drv_t>::uninit().assume_init();
// Basic initialization
lvgl_sys::lv_disp_drv_init(&mut disp_drv);
// Set your driver function
disp_drv.flush_cb = Some(display_callback_wrapper::<T>);
disp_drv.user_data = device as *mut _ as *mut cty::c_void;
disp_drv
};
// Assign the buffer to the display
disp_drv.buffer = display_buffer.as_mut_ptr();
// Finally register the driver
unsafe {
lvgl_sys::lv_disp_drv_register(&mut disp_drv);
}
Self {
raw: disp_drv,
display_buffer,
refresh_buffer,
phantom: &PhantomData,
}
}
pub fn get_active_screen(&mut self) -> ObjectX<'static> {
get_active_screen()
}
}
unsafe extern "C" fn display_callback_wrapper<T>(
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<Rgb888>,
{
// 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 device = &mut *(disp.user_data as *mut T);
for y in (*area).y1..=(*area).y2 {
for x in (*area).x1..=(*area).x2 {
// Convert C color representation to high-level Rust
let raw_color = *color_p.add(i);
i = i + 1;
let color = Rgb888::new(raw_color.ch.red, raw_color.ch.green, raw_color.ch.blue);
rafaelcaricio commented 2020-04-19 13:32:35 +00:00 (Migrated from github.com)
Review

I just could not figure out to make it more generic because of this line. We need a concrete type to instantiate the color.

I just could not figure out to make it more generic because of this line. We need a concrete type to instantiate the color.
// Callback the Rust closure to flush the new points to the screen
let _ = device.draw_pixel(drawable::Pixel(Point::new(x as i32, y as i32), color));
}
}
// Indicate to LittlevGL that you are ready with the flushing
lvgl_sys::lv_disp_flush_ready(disp_drv);
//}); // end of panic::catch_unwind
}
pub fn get_active_screen() -> ObjectX<'static> {
let raw =

View file

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