Some problems with V8

I am advancing translating the lvgl C examples to MicroPython:
get_started is done
style: 1-4 ok
5 does not exist in the C code
6 is essentially empty
7 -9 are ok
10 is completely commented in the C code
11 is ok
in layouts/flex: example_1: I tried to implement LV_PCT, which is defined as a
#define macro, in a Python function. The program works, but the button sizes are slightly different from the original
example_2: I cannot set LV_LAYOUT_FLEX
lv.mpy.c says:

  • Function NOT generated:
  • Missing conversion to uint32_t when generating global LV_LAYOUT_FLEX
    for the widgets:
    arc and bar are ok
    btn: example_1 ok
    example2: I do not understand how to define the transitions
    example3: not yet done
    calendar: I have problems with the headers. The pull-down menus do not appear, the arrow crashes the program
    btnmatrix: first example is ok, the others not started yet

Actually there’s lv.pct that replaces LV_PCT, so you can use that.

Yes, this is not supported yet but I’m going to implement it.


This problem is related to underscore in widget name, see:

@amirgon: Thanks. I tried lv.pct and it does the same thing as the function I had implemented.
Strangely enough there are subtle differences in the button sizes between the C version and the Python version of lv_example_flex_1. Here is the C version:
and here the Python version.
I think the vertical size of the buttons in the row is slightly bigger in the Python version while the vertical size of buttons in the column is bigger in the C version.
No clue why this is the case.
Is there any progress on the logging?
Even though Gabor said that he intended this mainly for lvgl proper, the fact that there is a log type “user” would tell me that it should also be available for user logs.
I also did not understand yet how I must treat style transitions. How do I have to define the list of properties (second parameter in lv_style_transition_dsc_init)?

Sorry, I have another problem:
In several places in the examples a lv_obj_draw_dsc_t is picked up from a callback event:
dsc = e.get_param()
Unfortunately this is a void pointer and seen as a blob in Python.
How do I get at the real thing?

I’m not sure, buy maybe lv_conf.h is different between them?

lv.log is available on the latest version, did you try it?
You first need to register a log printing function with lv.log_register_print_cb
You might also need to change LV_LOG_LEVEL in lv_conf.h to get info/trace logs from LVGL code itself.

I think this is a bug:

@kisvegabor could you change props to an array instead of pointer? (const lv_style_prop_t props[])

You can do something like this:

obj_draw_dsc = lv.obj_draw_dsc_t.cast(e.get_param())

A difference in LV_DPI_DEF can cause such an issue.

Fixed here. Sorry for the trouble.

There are 2 main cases when the event_param's type is a fixed type based on the event code:

  • LV_EVENT_DRAW_MAIN/POST_BEGIN/END set the const lv_area_t * clip_area (required if you draw something manually in the event)
  • LV_EVENT_DRAW_PART_BEGIN/END set to lv_obj_draw_dsc_t * to describe the part being drawn.

Adding dedicated functions (e.g. lv_event_get_param_draw_main(e)) is possible but looks ugly IMO.
Do you have a good naming idea or other ideas to make it simpler in MP?

Before starting any work I now pull the latest version of lvgl and lv_bindings every morning and every morning there are changes, which proves that we are advancing!
lv_conf.h in lv_micropython and lv_sim_eclipse_sdl are definitively different. I therefore copied lv_micropython’s lv_conf.h to the simulator. I had to make a few small changes in the memory settings and I had to disable the python garbage collector to make it work on the simulator. I did a make clean and rebuilt lv_example_flex_1 but did not see any change. LV_DPI_DEF is defined in lv_conf.h and is the same since I copied the file.
I have a similar problem on the canvas (here the C version)
and here the Python one:
@amirgon: I saw that lv.log is there, however I am too dumb to figure out how to use it.
I can register the log function ok, but how do I add something to the log? When I try
log = lv.log(…) says that the lambda needs 5 parameters?

Let me also report a success:

obj_draw_dsc = lv.obj_draw_dsc_t.cast(e.get_param())

works as expected.

It’s still possible to cast void* to <some struct>* in Micropython.
However, it is confusing for the Python user who is not used to C-idiom pointers and casting so we should try to avoid it, if possible.
Specifically, regarding the “get_param” case, I’m not entirely sure what’s the best approach. If the usage is rare and only required in advanced cases (such as pure Python widgets) then perhaps we could live with the casting.

The two options are:

  • With casting: obj_draw_dsc = lv.obj_draw_dsc_t.cast(e.get_param())
  • Without casting: obj_draw_dsc = e.get_param_draw_main()

I’m not sure what the problem is.
The Micropython bindings is eventually a thin layer that passes calls and data transparently between LVGL API and Micropython. It is not supposed to change anything so I would expect the visual result to be exactly the same.
I still think the problem might be related to some configuration. If it’s not lv_conf.h then maybe build configuration or display driver which is different etc.

Here is a simple example for using lv.log:

>>> lv.log_register_print_cb(lambda s: print('LOG: %s' % s))
>>> lv.log("Logging some data")
LOG: Logging some data

Like this logging looks simple. But… where does the log level come into play?
I remember that registering the print_cb looked like this in
log_level=[“Trace”, “Info”, “Warning”, “Error”, “User”]
lv.log_register_print_cb(lambda level,filename,line,func,msg: print(‘LOG: %s, file: %s in %s, line %d: %s’ % (log_level[level], filename, func, line, msg)))
I would not know however, how a user message would be logged.

I think that on v8 the log level is set entirely on compile time.
You set the log level you are interested in on lv_conf.h by setting LV_LOG_LEVEL. On the C code a log line is not even compiled if the log level is lower - so it saves program size.
See the LV_LOG_* macros on lv_log.h

I think that in Micropython we can have several options:

  • Call lv_log conditionally according to some global log level variable
  • Call lv_log anyway and decide if we register a log callback or not
  • Not use lv_log for Micropython logging, but some other Python specific logging mechanism.

In my opinion LVGL logging mechanism is useful mainly for seeing internal LVGL logs during debugging.

So, I understand that we cannot do something like LV_LOG_USER(“Clicked”) even if we define a global Python variable LOG_LEVEL = “USER”.
Which gives us a log like

If we cannot make use of lvgl’s log functionality then we should drop it altogether,

A global Python LOG_LEVEL = “USER” won’t affect LVGL log level, which is set on compile time on lv_conf.h.
We can do it the other way around - we can have a Python function that returns LVGL log level as defined in lv_conf.h (and that would be constant for a compiled image).

I think it’s useful just if you want to see LVGL logs (such as “lv_mem_init” log line you show above) intermixed and synchronized with your own Python log lines.

If you are not interested at all in LVGL internal logs then we might as well not use LVGL’s log functionality.

You are of course entirely right and I don’t see how we could pass through the lvgl logging mechanism to add user log messages, which would print filename, function and line number. These are dependent on the C code.
I therefore think we should just skip the log in the lvgl python binding.
If logs are needed we should use the micropython log found in the micropython-lib.
You may remember that I used this in the printer demo.

Yes, it’s only for advanced use cases. Let’s leave the “cast” version for now. We can improve it later.

About the logging

I think it’s not critical at this point. We can also decide it later when the other issues are fixed and our mid becomes freer. :slight_smile: