Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updating display from an independent context #149

Open
fulup-bzh opened this issue Aug 9, 2023 · 1 comment
Open

updating display from an independent context #149

fulup-bzh opened this issue Aug 9, 2023 · 1 comment

Comments

@fulup-bzh
Copy link

I'm trying to use lvgm-rs with an asynchronous framework and I miserably fail to find the good design pattern.

To expose something simple I restarted from demo/arc example. I try to split arc.rs with 3 functions.

  • 1st create display design and returning a handle containing: display, widget, ...
  • 2nd update the display from previously received handle
  • 3rd main that call both functions.

Note: doing so, we loose default RUST live cycle and everything created on the heap by 1st function disappear before calling second function.

The 1st issue to solve seems tp comes from screen.add_style(Part::Main, &mut screen_style); because of this screen depend on screen_style which is a Box that will be deleted at function return. But this might only be the visible part of the iceberg.

Any idea on how to implement a pattern to update the display from an asynchronous event would be more than welcome. Alternatively of you have some sample that could help, please let me known.

If we find a working solution, I commit to push an example on github, as I cannot be the only one with this need.

Handle + Main function

struct DisplayHandle<'a> {
    pub sim_display: SimulatorDisplay<Rgb565>,
    pub window: RefCell<Window>,
    pub screen: Screen<'a>,
    pub arc: RefCell<Arc<'a>>,
}

fn main() -> Result<(), LvError> {

    let handle= mk_display() ?;

    // handle.update should be callable from an asynchronous function (i.e. a system timer)
    display_update(handle)?;

    Ok(())
}

Function creating the display layout return a static/leak box to make sure the handle is never deleted

fn mk_display() -> Result< &'static DisplayHandle<'static>, LvError> {
    const HOR_RES: u32 = 240;
    const VER_RES: u32 = 240;

    println!("meminfo init: {:?}", mem_info());
    let mut sim_display: SimulatorDisplay<Rgb565> =
        SimulatorDisplay::new(Size::new(HOR_RES, VER_RES));

    let output_settings = OutputSettingsBuilder::new().scale(1).build();
    let window = Window::new("Arc Example", &output_settings);

    let buffer = DrawBuffer::<{ (HOR_RES * VER_RES) as usize }>::default();

    let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
        sim_display.draw_iter(refresh.as_pixels()).unwrap();
    })?;

    let mut screen = display.get_scr_act()?;

    let mut screen_style = Style::default();
    screen_style.set_bg_color(Color::from_rgb((255, 255, 255)));
    screen_style.set_radius(0);
    screen.add_style(Part::Main, &mut screen_style);

    // Create the arc object
    let mut arc = Arc::create(&mut screen)?;
    arc.set_size(150, 150);
    arc.set_align(Align::Center, 0, 10);
    arc.set_start_angle(135)?;
    arc.set_end_angle(135)?;

    let mut loading_lbl = Label::create(&mut screen)?;
    loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
    loading_lbl.set_align(Align::OutTopMid, 0, 0);
    //loading_lbl.set_label_align(LabelAlign::Center)?;

    let mut loading_style = Style::default();
    loading_style.set_text_color(Color::from_rgb((0, 0, 0)));
    loading_lbl.add_style(Part::Main, &mut loading_style);

    let handle = Box::new(DisplayHandle {
        screen,
        sim_display,
        window: RefCell::new(window),
        arc: RefCell::new(arc),
    });
   // make sure the handle is never going to be deleted
    Ok(Box::leak(handle))
}

For my test, the update function is called directly from main routine, my end goal is call it from an asynchronous timer event, that potentially run in a different thread.

fn display_update (handle: &DisplayHandle) -> Result <(), LvError> {
    let mut angle = 0;
    let mut forward = true;
    let mut i = 0;

    // retrieve mutable arc handle from display handle
    let mut arc= handle.arc.borrow_mut();
    let mut window= handle.window.borrow_mut();

    'running: loop {
        let start = Instant::now();
        if i > 270 {
            forward = if forward { false } else { true };
            i = 1;
            println!("mem info running: {:?}", mem_info());
        }
        angle = if forward { angle + 1 } else { angle - 1 };

        arc.set_end_angle(angle + 135)?;
        i += 1;

        lvgl::task_handler();
        window.update(&handle.sim_display);

        // for event in window.events() {
        //     match event {
        //         SimulatorEvent::Quit => break 'running,
        //         _ => {}
        //     }
        // }
        sleep(Duration::from_millis(15));
        lvgl::tick_inc(Instant::now().duration_since(start));
    }
}
@fulup-bzh
Copy link
Author

To help in reproducing my problem, I pushed my code on https://github.com/fulup-bzh/lvgl-async-rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
@fulup-bzh and others