-
Notifications
You must be signed in to change notification settings - Fork 49
add_event_cb #1
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
Comments
your syntax is wrong..
you had the parenthesis on the function as if you were calling it. |
scratch that last comment. I am not sure why you are doing what you are doing. |
you should be able to do
The reason why you are having an issue is because the returned function went out of scope so it ended up getting garbage collected. You need to keep the function you are passing to the callback in scope. |
|
let me look into it. not sure why it is doing that. I think I may know the reason but not 100% sure. |
The error message "Cannot convert 'function' to pointer!" suggests that you're trying to convert a Python function to a C function pointer, which is not directly possible in MicroPython. In your mp_lv_obj_add_event_cb function, you're using mp_to_ptr(mp_args[1]) to convert the second argument to a function pointer (lv_event_cb_t event_cb). If this argument is a Python function, you'll get the error you're seeing. To fix this, you need to create a C function that can be called from your C code, and that calls the Python function. This is typically done using the mp_call_function_n_kw function in MicroPython, which allows you to call a Python function from C. I am try for test - add code like this. Now works. But I am direct change code in lv_mp.c. How that generate from script ?
|
OK so I id some digging and I found the source of the problem. The problem is upstream and not in my code. The issue is in LVGL's code. In version v9.0.0 there has been a push to make a bunch structures private. The issue is the binding script looks at the fields in the structures to see if there is a "user_data" field. That is where the python function gets stored. You can watch this issue Once it is fixed upstream I can change the submodule pointer so it will correct the problem downstream. I had advised against making the structures private for this exact reason. That advisement fell on deaf ears and this would be the result. Gonna have to change a lot of things in the generation script to get it to work. I also have to go digging through all of the LVGL code to see what else has been made private that is going to break things. At this point I am ready to throw in the towel with doing anything with MicroPython and LVGL because no one wants to listen to me. It is going to be quite the large undertaking to code around this issue because of how the gen_mpy script was written, it's a mess. If I was going to spend the time I would spend it on rewriting the entire gen_mpy script. I do not think I would make it publicly available if I did. So basically what needs to happen is the structures that were made private need to be made public again and if that doesn't happen than this repo is going to be a dead stick. |
I already read about private methods yesterday. I also thought, well, it can't be that they left it like that in 9. They did. |
I had said on more than one occasion that making a structure private that gets used in a public function or structure/union is going to cause issues that is not going to be easily fixed. If they want to keep the structures private there is one other way it can be done and that is adding a user_data parameter to the callback function prototypes. That means that every single place that either registers a callback or calls a callback is going to have to get updated. Those are the only 2 ways to make it work. A while back I had suggested using a common structure to hold callbacks and using macros to initialize the structure. This way the userdata gets packaged with the callback function in a nice simple to identify package. something along these lines / macro to initialize cb_t structure
#define event_cb_t(f, ud) { .func=(void *)(callback_function_prototype)f, .user_data = ud }
// structure that holds the callback function and the user data
typedef struct {
void *func;
void *user_data;
} cb_t;
// this structure would be private so it's fields would not be known.
typedef struct {
cb_t *callback;
} some_hidden_structure;
// callback function prototype
void (* callback_function_prototype)(some_hidden_structure *obj, cb_t *cb_data);
// register function
void some_register_callback_function(some_hidden_structure *obj, cb_t *callback) {
obj->callback = callback;
}
// user created callback function
void some_callback_function(some_hidden_structure *obj, cb_t *callback) {
// access the user_data
char *user_data = (char *)callback->user_data;
}
// create user data if needed
char user_data[] = "some user data\0";
// create the callback object
cb_t some_event_callback = event_cb_t(some_callback_function, some_user_data);
some_hidden_structure *some_obj;
// register the callback
some_register_callback_function(some_obj, &some_event_callback)
// calling the callback that has been stored. this would be used internally in lvgl
(callback_function_prototype)some_obj->callback->func(some_obj, some_obj->callback) something along those lines. by doing this it pairs all callbacks with user data and all callbacks now have the same type. This makes is easier to create a binding because the only thing that needs to be looked for is the use of the type doing this also reduces the amount of memory used if registering the same function over and over again to different objects. instead of having a user data pointer and callback pointer in each structure now there is only a single pointer. 4 bytes less data consumed for each object. |
I believe I might have a way to get it to work, it's kind of hackish but it should work. |
OK so good news. it's fixed. I have not yet updated the repo and I will be doing that after I remove the debugging code I had added. I also had to fix the unix port so it would compile and I will be pushing those changes as well. I have to get the stuff that I changed copied over. |
well apparently my fix didn't fix just the event callback. It fixed a bunch of things that were broken. That's actually a good thing. I knew there were structures that had fields in them that were never defined in the binding. What I did fixed those as well as not all of the structures having I don't know if what I did broke anything as I only tested the event callback and it worked. |
Thanks. I will some test. |
the issue is pycparser which is what is used to read the LVGL source code and build the micropython source code. when you have code like this
This is read by pycparser as
in lv_types.h you have the script that generates the code looks for lv_event_t and the first one it finds is what gets used. Unfortunately in the case of forward declarations there are not going to be any fields in the structure. Those don't get added until much later in the processing of the code. So what I did was I iterated over all of the python objects that represent the different pieces of C code and I specifically looked for typedefs to collect the structure name from them only if there were no fields defined. I also looked for declarations of structures that did have fields and if the name matched the name of the structure in the typedef I moved the fields over to the typedef and deleted the decl of the struct. This allows the fields to be visible so the correct handling of callbacks can be done. |
I did but together a way around the whole private thing as well. I have the build script create a header file that includes lvgl.h and also the private header files. That coupled with the code I added to fix the callbacks correctly adds all of the fields for the private structure. What I need to check on is if the fields are added to the classes properly or are they added to a completely separate object. |
Work very well. With asyncio. Animation work.
|
fantastic!!! |
and with the newest change I am going to push shortly all of the fields for all of the structures will be exposed to micropython. everything except for the fields for the widgets. I am working on how to go about handling that. By having those things it will make LVGL a lot more flexible to use in MicroPython. |
Some test. |
I hope you do understand that asyncio is a complete waste of resources when not dealing with something related to transmitting and receiving data over say a network. Using it for anything to do with LVGL is not going to offer you anything except a lot of additional overhead and also slower running code. All of asyncio in Micropython is written in python and not in C code. |
Never mind. It doesn't bother me. I can do it without ayncio and with asyncio. The main thing is that it works. |
If you want to see how fast LVGL is take a look at this. LVGL rendering on a desktop PC with a resolution of 450 x 450. Rendering 56 arcs and each arc is set for 0 to 360 degrees total range and the value of each arc and the rotation of each arc changes for each frame as fast as one core on my PC is able to. The arcs also have a different color, opacity, starting rotation angle and starting value. The increments for both rotation and value for each arc is randomly selected. https://www.youtube.com/watch?v=t2fY8c_SfjA and here is a speed test with it running on an ESP32 with a 480x320x16 display over SPI. and here is one of full screen updates running on the same hardware as above https://www.youtube.com/watch?v=35j4p78OJAs The last 2 examples are running using a modified version of the MicroPython binding. It handles the priority of touch and rendering differently. I eliminated the refresh timer and it check to see if anything needs to be redrawn instead. It is a much better way of handling the updates. |
Some people are used to asyncio and like to use it. the problem is that it ends up getting used for everything. It states right in the name what it is for "Asynchronous Input Output" Everything in LVGL is synchronous. Since you are using the ESP32 you should look into using the _thread module. The ESP32 does support threading. Now you can't use it for updating anything in LVGL but what you can use it for reading sensor data or reading/setting pin states. that kind of thing. |
Nice Video. |
yeah, it got broken again upstream... No one seems to want to listen to me with regards to how the binding works and that making structures private is going to cause issues. I have written some code that is going to be used to work around the issue because that code is able to read the private header files without generating any binding code. we are aware of the problem and it has been fixed, just waiting for the PR to get merged. There are a very large number of changes that are taking place in LVGL for the soon to be released version. Once that version is released I am going to do an official release of this binding and lock it to using IDF 5.2.x, LVGL 9.2.x (might be 9.2.x i have to check) and MicroPython 1.23.x. The next version I release is going to have some pretty large API changes made to it so the naming makes a little more sense. For example... To start an LCD display. for SPI it would be.
It is going to be tricky to return the python display driver from C code but I think I am going to be able to do it by using the display driver name to load the matching module. There will be machine.I8080 and machine.RGB classes as well. |
@kdschlosser , I'm glad to hear that the issue has been fixed again :) , I can't wait for the release. I'v read a lot of discussions about it while track down this issue at lvgl/lvgl/pull/6068 , I'm hate to see work get done and then have to get done again too. |
esp32. LVGL works - button can draw without event.
line 65, in btn_reset_gen
SyntaxError: Cannot convert 'function' to pointer!
The text was updated successfully, but these errors were encountered: