Crash when button matrix is manipulated in another button's callback function

Description

The TFT Simulator crashes when I enter a callback function making changes to a button matrix (when I click a button which has the below detailed callback function.

What MCU/Processor/Board and compiler are you using?

PC Simulator, LVGL lib actual master

What do you want to achieve?

To make the button matrix inactive in case of a toggled button.

What have you tried so far?

See the code below.

Code to reproduce

Callback called when a button is clicked. In case button is toggled, the btnmFeederMove button matrix shall be set to inactive. is defined as:

static lv_obj_t * btnmFeederMove;

The callback function looks like:

static void callBack_btnAutoManual(lv_obj_t * btn, lv_event_t event)
{
	lv_btn_state_t stateBtnAutoManual;
    if(event == LV_EVENT_CLICKED) {
    	stateBtnAutoManual = lv_btn_get_state(btn);
    	switch(stateBtnAutoManual)
    	{
    		case LV_BTN_STATE_TGL_REL:
    			lv_label_set_text(lblBtnAutoManualMode,"MANUAL");
    			lv_btnm_clear_btn_ctrl_all(btnmFeederMove,LV_BTNM_CTRL_INACTIVE);
    			break;

    		default:
    			break;
    	}
    }
}

Screenshot and/or video

Standard .exe crash screen.

I tried this example, and while mine doesn’t crash it also doesn’t actually set all of the buttons in the matrix to the Inactive state. This is not something I have tried yet so I am not sure what I am missing, and unfortunately I do not have a lot of time to test this out today - sorry about that.

My only thought as to what is causing your code to crash is you have an uninitialized pointer. From what I can see you need to verify that both lblBtnAutoManualMode and btnmFeederMove have been initialized.

For your reference this is the code I tried out:

static void event_handler(lv_obj_t *obj, lv_event_t event);
static void callBack_btnAutoManual(lv_obj_t * btn, lv_event_t event);

static const char * btnm_map[] = {"1", "2", "3", "4", "5", "\n",
                                  "6", "7", "8", "9", "0", "\n",
                                  "Action1", "Action2", ""};

static lv_obj_t *btnmFeederMove;
static lv_obj_t *manual;
static lv_obj_t *lblBtnAutoManualMode;

void menu_create(void)
{
    manual = lv_btn_create(lv_scr_act(), NULL);
    lv_obj_set_event_cb(manual, callBack_btnAutoManual);
    lv_btn_set_toggle(manual, true);
    lblBtnAutoManualMode = lv_label_create(manual, NULL);
    lv_label_set_text(lblBtnAutoManualMode, "AUTO");

    btnmFeederMove = lv_btnm_create(lv_scr_act(), NULL);
    lv_btnm_set_map(btnmFeederMove, btnm_map);
    lv_btnm_set_btn_width(btnmFeederMove, 10, 2);        /*Make "Action1" twice as wide as "Action2"*/
    lv_obj_align(btnmFeederMove, NULL, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_event_cb(btnmFeederMove, event_handler);
}

static void event_handler(lv_obj_t * obj, lv_event_t event)
{
    if(event == LV_EVENT_VALUE_CHANGED) {
        const char * txt = lv_btnm_get_active_btn_text(obj);

        printf("%s was pressed\n", txt);
    }
}

static void callBack_btnAutoManual(lv_obj_t * btn, lv_event_t event)
{
	lv_btn_state_t stateBtnAutoManual;
    if(event == LV_EVENT_CLICKED) {
    	stateBtnAutoManual = lv_btn_get_state(btn);
    	switch(stateBtnAutoManual)
    	{
    		case LV_BTN_STATE_TGL_REL:
    			lv_label_set_text(lblBtnAutoManualMode,"MANUAL");
    			lv_btnm_clear_btn_ctrl_all(btnmFeederMove,LV_BTNM_CTRL_INACTIVE);
    			break;

    		default:
    			break;
    	}
    }
}

You mentioned you are using the PC simulator. I suggest debugging the callback code and stepping through this code to figure out which line is calling the segfault. As I mentioned I suspect this is pointer-related.

Looks like it chrashes when it comes to lv_btnm_clear_btn_ctrl_all. It enters the following function, and crashes at the return statement.

 void * lv_obj_get_ext_attr(const lv_obj_t * obj)
{
    return obj->ext_attr;
}

Solution: you were right, there was problem with the initialization. I wrote
lv_obj_t * btnmFeederMove = lv_btnm_create(contColumn, NULL);, but should wrote:
btnmFeederMove = lv_btnm_create(contColumn, NULL); as it was already declared as a global variable outside the function.
Thanks for the hint!

1 Like

With this line you have “cleared the inactive state” from all buttons.
To set the inactive state you should use lv_btnm_set_btn_ctrl_all.

In this case probably obj is not initialized (NULL?). I also suggest running the code in debugger to see the values of obj.