I have a few wrapper classes I use for my project. Most of my elements are recurring so those classes make my code a lot cleaner. My label class has a
setFont() function that is giving me some headache. Usually i would declare my styles as
static, apparently in a class this would not work unless i want all elements to have the same style. But declaring the style as a variable of the class is giving me a bunch of crashes I am unable to track down. Odd sidenote: if I debug the code to see what’s crashing there is no crash happening (no kidding), but the fonts are also not applied.
So what would make most sense to me is to
lv_style_init()the style in the class constructor and
lv_obj_add_style() it to the classes lv_obj (which in this case is an lv_label). However if I do so my ESP32 crashes, I’ve read the docs and found
lv_obj_refresh_style(this->obj, LV_STYLE_TEXT_FONT);, however calling this does not change the behavior I am observing.
The closest I can get to pinning down the crash is it’s likely happening in the draw code. When I restart the crashed ESP the backlight turns on briefly and shows a correctly drawn header of my main window and corrupted image data (color noise) in the rest of the display.
So, what would be the proper way to do what I would like to do?
(v7 is great by the way!)
lv_conf.h. It will assert if you have uninitalized styles.
Yes indeed the assertion triggers.
So apparently this sequence does not work
lv_obj_add_style(this->obj, part &this->style);
lv_style_set_text_font(this->style, LV_STATE_DEFAULT, &font);
the assertion gets triggered at
My impression was that with the new style system we can change styles on the fly that are already added to an object?
Why am I trying to do it this way? Because I’d like my class to be able to adjust a font to a new one on the fly, instead of assigning a new cascade every time the font is changed, as that seems rather inefficient, as it would end up with all the fonts assigned but only the last one used …
So the question is, how would this be done the proper way? Apparently I am doing it wrong
Did you type that code sample out by hand or is that what you’re currently using? I ask because I may have found the issue.
this->style should be an
lv_style_t, not an
With the call to
lv_style_set_text_font you aren’t taking it’s address and instead treating it as though it is already an
i am typing it out by hand, it would not compile otherwhise
also if I move the add style from the constructor to after set_text_font in the setFont() it works as expected. If I call
lv_obj_add_style() the assertion triggers.
I’ll test it in a few minutes.
For me, both sequences work without crashing; however, if I add the style and then set the font, the label doesn’t resize to accommodate the larger text. I would expect that to be the case, as for performance reasons, you have to tell the label that the style actually changed.
It still doesn’t explain why it’s crashing for you though. (I have memory protection and asserts enabled, so I don’t think there is any uncaught undefined behavior, although one can never be too sure. )
I finally realized there’s a bunch of useful asserts, i fixed some string problems, but i am unable to solve this problem.
Even worse. To get more progress with my project I actually skipped this and accepted that I can only set the style once. All my attempts on fixing it resulted in behavior I cannot explain to myself - like errors in release build and none while debugging.
I now have another flavor of the problem to add that I have a feeling may contribute in finding out what’s wrong here …
This code inside my Spinbox class constructor:
this->spinbox = lv_spinbox_create(this->obj, NULL);
lv_spinbox_set_digit_format(spinbox, 6, 4);
lv_style_set_pad_top(&spinboxStyle, LV_STATE_DEFAULT, 10);
lv_obj_add_style(this->spinbox, LV_SPINBOX_PART_BG, &spinboxStyle);
thows this assertion:
lib/lvgl/src/lv_core/lv_debug.c@97->Invalid style (local variable or not initialized?)
lib/lvgl/src/lv_core/lv_debug.c@188->Invalid style (0x3FFB1EF8)
this->obj is an lv_container instance. and
spinboxStyle is an
lv_style_t defined as a class member. The only sense I can make from this currently that it has to do with having an lv_style_t defined in a class, but I have absolutely no clue why
It really sounds like either there’s memory corruption or your class is being deallocated.
I am afraid memory corruption it is. trying to find out which portion of the code it is. already replaced all sprintfs with snprintf to make sure its no overflow. having little to no experience with this i am a bit f* right now i guess …
You can try setting a watchpoint on the style’s
sentinel value. If it’s a repeatable issue the debugger will likely alert you as to what part of your code is corrupting it.
Just a suggestion.
any suggestion is very very welcome at this point. I am not sure if my debugger is able of this … (vscode, platformio with open ocd and esp-prog). When I put the sentinel or the spinboxstyle in my watch list I am actually getting map 0x0 and sentinel 0, although in the local variables view it all looks correctly initialized.
Hmm… it looks like the underlying debug hardware supports watchpoints (as does OpenOCD), but I can’t find much information on how to make use of them with PlatformIO’s debugger.
If PlatformIO uses the same terminology as other debuggers, I’m pretty sure the watch list is just a handy way for you to see the values of other variables. It doesn’t actually add a breakpoint.
Are you familiar at all with GDB itself (the CLI equivalent)?
I know what it is but have never used it. Familiar would be stretching it I guess
But it sounds like a smart way to get hold of the problem!
Is there by chance a “debug console” window that appears when you’re debugging? If so, can you try typing
help or a similar generic command in to see if it accepts GDB commands?
yes indeed there is! I can call
watch Gui.qnhSpinbox.spinboxStyle.sentinel and it reports
Hardware watchpoint 3: Gui.qnhSpinbox.spinboxStyle.sentinel
All I’m getting is the debugger crashing o.O
What kind of expression would you suggest should work? Maybe even put in the memory address and number of bytes to watch?
I’ve managed to watch the address of the sentinel. What puzzles me is that inside the class constructor, the debugger returns a different address to the sentinel than after the debugger (
&this->spinboxStyle->sentinel inside the constructor returns
&Gui.qnhSpinbox.spinboxStyle.sentinel after the constructor returns
0x3ffc0848. Also the 4 bytes starting at the first memory address get overwritten constantly in almost every function call.
Looking at this it’s no surprise it’s not working. But then if I am not mistaken this brings along a whole lot of other problems with using the constructor for initialization … this is not how I would expect a constructor to behave, but i also would not consider myself an experienced C/C++ developer
any ideas about this?
It means that either
spinboxStyle is changing,
this is changing, or
Gui.qnhSpinbox is changing. Try setting a watchpoint on one of those.
this. Apparently the constructor is running in a specific (fast access?) memory region (0x3ffb…) and after the constructor the instance is copied to a different memory region (0x3ffc…). So any address of an instance member that get’s passed during the constructor is invalid after the constructor is finished. I’ve solved it by renaming the constructor into an init() function. Instead of call the constructor I call the init function and everything works as expected.
Fortunately I learned a bunch about memory along the troubleshooting process so I can account it on study time instead of stale time. thanks for your help embeddedt!
No problem. The behavior you described is really strange; I don’t know if you are using virtual classes or something similar that might cause that. Anyways, we both learned something new!