Rust Bindings for LittlevGL

Hi all,

I just wanted to share that I have started to write safe bindings for Rust to use LittlevGL. This project makes it easy and idiomatic to write LittlevGL based applications in Rust.

The project is still in it’s initial state, but I was able to actually run in an embedded device and see the widgets.

I have also available in the repo, examples of the library working with a simulator. Having a simulator makes it possible to write and run your projects in Rust using lvgl-rs in your desktop, then use the exact same code to run on your embedded device (taken you’ve abstracted everything that is not dependent on hardware).

Let me know what you think. I am happy to accept contributions! :slight_smile:
I hope you will enjoy!

1 Like

That’s amazing!

How do you create the binding? Do you have a script or do it manually?

1 Like

Thank you!

It’s mostly a manual process.

The way to start is to use rust-bindgen tool to generate the “low level” code that binds to the exported interface of the C library. That generated binding is “unsafe” as it can only be called inside unsafe {} blocks in Rust. That is the only generated part and the starting point of the process.

After that, we need to craft manually the safe & idiomatic Rust API on top of the unsafe bindings. That’s where a lot of manual work and attention needs to be invested. We need to translate the C library types to Rust types and all the other guarantees, like if the library is not safe to use in threaded environments, etc.

I was heavily inspired by this blog post. Also I saw that most of the PineTime opensource OSs were already using LVGL and there was no Rust bindings available yet. So I decided to create the LVGL Rust bindings library. :slight_smile:

It is still very much a work in progress, but it already works for the widgets that are implemented. Yesterday, I finished upgrading it to the new style system of LVGL 7.

All the help is welcome, in case you or anyone wants to participate. It is a hobby project for me as I’m not a full-time embedded developer. I really like embedded development and Rust, so I like to play with that whenever I get some free time.

I would like to participate as I’m new to Rust and learn more easily while doing. Do you have some sort of TODO list?

Hey @Carlos_Diaz! That’s awesome you want to join. We have a long to do list, as LVGL supports so many widgets we need to create the Rust API for them.

You can see the list here https://github.com/rafaelcaricio/lvgl-rs#widgets The widgets not marked are the missing ones. So you can see how to start by looking at the lvgl-rs/src/widgets folder. A simple example is the Gauge widget. You can see also we created a Rust enum for the parts, that should be also created for the widget you choose to create, if they have parts. You can start and open a PR when you have something and we can continue from there. :wink:

1 Like

The widget code looks like it could be generated automatically. It might be worth exploring this avenue more before committing to several hours of manual work.

I’ve never used Rust before, but the set_value argument types map directly to the equivalent C99 integer types, and the enum logic also looks easy to template. We’d just need a suitable C parser (the MicroPython bindings script uses https://github.com/eliben/pycparser, I don’t know if you are familiar with the Rust counterpart).

1 Like

Yeah, actually now looking at the code to reply to @Carlos_Diaz I realised that many code parts seem duplicated right now. So I simplified greatly the code necessary to port the widgets. Now to port the btn just just:

define_object!(Btn, lv_btn_create);

I also changed the name convention to follow exactly LVGL code.

I will look into also creating a macro for the enum conversions. Probably that can also be automated. That is a good idea. I will look closer at the Python port as well.

I did start some rudimentary code generation based directly on the C99 code. It could also be solved with Rust procedural macros, but IDEs don’t have auto-complete support for it yet. So I decided to just generate raw code. Another motivation was also that the rust-bindgen do not convert C macros to Rust.

@ioctl
Glad to hear that you already integrated the new styles system. :rocket:

I think, by “The widget code looks like it could be generated automatically” @embeddedt meant that, it’s possible to run a script on the source code of LVGL, parse it and automatically generate the binding’s code.

It has the advantages of

  1. Less initial work: should be faster than manually writing binding to all functions
  2. Less error-prone: can avoid human error
  3. Easier maintenance: just run the script again on a new version of LVGL to create the new binding

I think once you have explored how the binding could work, the task for binding generation is mainly to find a suitable C parser library (e.g. pycparser), get familiar with it and utilize it. What do you think about it?

Having a new binding to LVGL would be awesome and very welcome! If you want we can open a new repo for it in lvgl organization, and officially promote it once it’s ready.

1 Like

Sure, generation for most of the code is the path I’m pursuing now. Makes a lot of sense. I’m trying some different approaches for the code generation and will be able to release something soon™️.

Great! :slight_smile: Please keep us updated!

I just wanted to give a quick update. I was playing around to make the LVGL Rust bindings able to compile to WASM and run on the browser. Here is the live example working: https://rafaelcaricio.github.io/lvgl-rs-wasm/
It is a simple example as LVGL Rust bindings are still in development.

The source code for anyone interested is available here: https://github.com/rafaelcaricio/lvgl-rs-wasm