Messaging

Messaging (lv_msg) is a classic publisher subscriber implementation for LVGL.

IDs

Both the publishers and the subscribers needs to know the message identifiers. In lv_msg these are simple integers. For example:

#define MSG_DOOR_OPENED             1
#define MSG_DOOR_CLOSED             2
#define MSG_USER_NAME_CHANGED       100
#define MSG_USER_AVATAR_CHANGED     101

You can organize the message IDs as you wish.

Both parties also need to know about the format of the payload. E.g. in the above example MSG_DOOR_OPENED and MSG_DOOR_CLOSED might have no payload but MSG_USER_NAME_CHANGED can have a const char * payload containing the user name, and MSG_USER_AVATAR_CHANGED a const void * image source with the new avatar image.

To be more precise the message ID`s type is declared like this:

typedef lv_uintptr_t lv_msg_id_t;

This way, if you a value in stored in a global variable (e.g. the current temperature) then the address of that variable can be used as message ID too by simply casting it to lv_msg_id_t. It saves the creation of message IDs manually as the variable itself serves as message ID too.

Subscribe to a message

lv_msg_subscribe(msg_id, callback, user_data) can be used to subscribe to message.

Don't forget that msg_id can be a constant or a variable address too:

lv_msg_subscribe(45, my_callback_1, NULL);

int v;
lv_msg_subscribe((lv_msg_id_t)&v, my_callback_2, NULL);

The callback should look like this:


static void user_name_subscriber_cb(lv_msg_t * m)
{
    /*m: a message object with the msg_id, payload, and user_data (set during subscription)*/

    ...do something...
}

From lv_msg_t the followings can be used to get some data:

  • lv_msg_get_id(m)

  • lv_msg_get_payload(m)

  • lv_msg_get_user_data(m)

Subscribe with an lv_obj

It's quite typical that an LVGL widget is interested in some messages. To make it simpler lv_msg_subsribe_obj(msg_id, obj, user_data) can be used. If a new message is published with msg_id an LV_EVENT_MSG_RECEIVED event will be sent to the object.

For example:

lv_obj_add_event_cb(user_name_label, user_name_label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
lv_msg_subsribe_obj(MSG_USER_NAME_CHANGED, user_name_label, NULL);

...

void user_name_label_event_cb(lv_event_t * e)
{
    lv_obj_t * label = lv_event_get_target(e);
    lv_msg_t * m = lv_event_get_msg(e);
    lv_label_set_text(label, lv_msg_get_payload(m));
}

Here msg_id also can be a variable's address:

char name[64];
lv_msg_subsribe_obj(name, user_name_label, NULL);

Unsubscribe

lv_msg_subscribe returns a pointer which can be used to unsubscribe:

void * s1;
s1 = lv_msg_subscribe(MSG_USER_DOOR_OPENED, some_callback, NULL);

...

lv_msg_unsubscribe(s1);

Send message

Messages can be sent with lv_msg_send(msg_id, payload). E.g.

lv_msg_send(MSG_USER_DOOR_OPENED, NULL);
lv_msg_send(MSG_USER_NAME_CHANGED, "John Smith");

To update a variable

Example

Slider to label messaging

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES

/*Define a message ID*/
#define MSG_NEW_TEMPERATURE     1

static void slider_event_cb(lv_event_t * e);
static void label_event_cb(lv_event_t * e);

/**
 * A slider sends a message on value change and a label display's that value
 */
void lv_example_msg_1(void)
{
    /*Create a slider in the center of the display*/
    lv_obj_t * slider = lv_slider_create(lv_scr_act());
    lv_obj_center(slider);
    lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);

    /*Create a label below the slider*/
    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_obj_add_event_cb(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
    lv_label_set_text(label, "0%");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 30);

    /*Subscribe the label to a message. Also use the user_data to set a format string here.*/
    lv_msg_subscribe_obj(MSG_NEW_TEMPERATURE, label, "%d °C");
}

static void slider_event_cb(lv_event_t * e)
{
    /*Notify all subscribers (only the label now) that the slider value has been changed*/
    lv_obj_t * slider = lv_event_get_target(e);
    int32_t v = lv_slider_get_value(slider);
    lv_msg_send(MSG_NEW_TEMPERATURE, &v);
}

static void label_event_cb(lv_event_t * e)
{
    lv_obj_t * label = lv_event_get_target(e);
    lv_msg_t * m = lv_event_get_msg(e);

    const char * fmt = lv_msg_get_user_data(m);
    const int32_t * v = lv_msg_get_payload(m);

    lv_label_set_text_fmt(label, fmt, *v);
}

#endif

MicroPython code  

 GitHub Simulator

# Define a message ID
MSG_NEW_TEMPERATURE = const(1)

# Define the object that will be sent as msg payload
class Temperature:
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return f"{self.value} °C"

def slider_event_cb(e):
    slider = e.get_target()
    v = slider.get_value()
    # Notify all subscribers (only the label now) that the slider value has been changed
    lv.msg_send(MSG_NEW_TEMPERATURE, Temperature(v))

def label_event_cb(e):
    label = e.get_target()
    msg = e.get_msg()
    # Respond only to MSG_NEW_TEMPERATURE message
    if msg.get_id() == MSG_NEW_TEMPERATURE:
        payload = msg.get_payload()
        temprature = payload.__cast__()
        label.set_text(str(temprature))

# Create a slider in the center of the display
slider = lv.slider(lv.scr_act())
slider.center()
slider.add_event_cb(slider_event_cb, lv.EVENT.VALUE_CHANGED, None)

# Create a label below the slider
label = lv.label(lv.scr_act())
label.add_event_cb(label_event_cb, lv.EVENT.MSG_RECEIVED, None)
label.set_text("0%")
label.align(lv.ALIGN.CENTER, 0, 30)

# Subscribe the label to a message
lv.msg_subscribe_obj(MSG_NEW_TEMPERATURE, label, None)

Handling login and its states

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES

/*Define a message ID*/
#define MSG_LOGIN_ATTEMPT   1
#define MSG_LOG_OUT         2
#define MSG_LOGIN_ERROR     3
#define MSG_LOGIN_OK        4

static void auth_manager(lv_msg_t * m);
static void textarea_event_cb(lv_event_t * e);
static void log_out_event_cb(lv_event_t * e);
static void start_engine_msg_event_cb(lv_event_t * e);
static void info_label_msg_event_cb(lv_event_t * e);

/**
 * Simple PIN login screen.
 * No global variables are used, all state changes are communicated via messages.
 */
void lv_example_msg_2(void)
{
    lv_msg_subscribe(MSG_LOGIN_ATTEMPT, auth_manager, "hello");

    /*Create a slider in the center of the display*/
    lv_obj_t * ta = lv_textarea_create(lv_scr_act());
    lv_obj_set_pos(ta, 10, 10);
    lv_obj_set_width(ta, 200);
    lv_textarea_set_one_line(ta, true);
    lv_textarea_set_password_mode(ta, true);
    lv_textarea_set_placeholder_text(ta, "The password is: hello");
    lv_obj_add_event_cb(ta, textarea_event_cb, LV_EVENT_ALL, NULL);
    lv_msg_subscribe_obj(MSG_LOGIN_ERROR, ta, NULL);
    lv_msg_subscribe_obj(MSG_LOGIN_OK, ta, NULL);
    lv_msg_subscribe_obj(MSG_LOG_OUT, ta, NULL);

    lv_obj_t * kb = lv_keyboard_create(lv_scr_act());
    lv_keyboard_set_textarea(kb, ta);

    lv_obj_t * btn;
    lv_obj_t * label;

    /*Create a log out button which will be active only when logged in*/
    btn = lv_btn_create(lv_scr_act());
    lv_obj_set_pos(btn, 240, 10);
    lv_obj_add_event_cb(btn, log_out_event_cb, LV_EVENT_ALL, NULL);
    lv_msg_subscribe_obj(MSG_LOGIN_OK, btn, NULL);
    lv_msg_subscribe_obj(MSG_LOG_OUT, btn, NULL);

    label = lv_label_create(btn);
    lv_label_set_text(label, "LOG OUT");

    /*Create a label to show info*/
    label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "");
    lv_obj_add_event_cb(label, info_label_msg_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
    lv_obj_set_pos(label, 10, 60);
    lv_msg_subscribe_obj(MSG_LOGIN_ERROR, label, NULL);
    lv_msg_subscribe_obj(MSG_LOGIN_OK, label, NULL);
    lv_msg_subscribe_obj(MSG_LOG_OUT, label, NULL);

    /*Create button which will be active only when logged in*/
    btn = lv_btn_create(lv_scr_act());
    lv_obj_set_pos(btn, 10, 80);
    lv_obj_add_event_cb(btn, start_engine_msg_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
    lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
    lv_msg_subscribe_obj(MSG_LOGIN_OK, btn, NULL);
    lv_msg_subscribe_obj(MSG_LOG_OUT, btn, NULL);

    label = lv_label_create(btn);
    lv_label_set_text(label, "START ENGINE");

    lv_msg_send(MSG_LOG_OUT, NULL);
}

static void auth_manager(lv_msg_t * m)
{
    const char * pin_act = lv_msg_get_payload(m);
    const char * pin_expexted = lv_msg_get_user_data(m);
    if(strcmp(pin_act, pin_expexted) == 0) {
        lv_msg_send(MSG_LOGIN_OK, NULL);
    }
    else {
        lv_msg_send(MSG_LOGIN_ERROR, "Incorrect PIN");
    }

}

static void textarea_event_cb(lv_event_t * e)
{
    lv_obj_t * ta = lv_event_get_target(e);
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_READY) {
        lv_msg_send(MSG_LOGIN_ATTEMPT, lv_textarea_get_text(ta));
    }
    else if(code == LV_EVENT_MSG_RECEIVED) {
        lv_msg_t * m = lv_event_get_msg(e);
        switch(lv_msg_get_id(m)) {
            case MSG_LOGIN_ERROR:
                /*If there was an error, clean the text area*/
                if(strlen(lv_msg_get_payload(m))) lv_textarea_set_text(ta, "");
                break;
            case MSG_LOGIN_OK:
                lv_obj_add_state(ta, LV_STATE_DISABLED);
                lv_obj_clear_state(ta, LV_STATE_FOCUSED | LV_STATE_FOCUS_KEY);
                break;
            case MSG_LOG_OUT:
                lv_textarea_set_text(ta, "");
                lv_obj_clear_state(ta, LV_STATE_DISABLED);
                break;
        }
    }
}

static void log_out_event_cb(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_CLICKED) {
        lv_msg_send(MSG_LOG_OUT, NULL);
    }
    else if(code == LV_EVENT_MSG_RECEIVED) {
        lv_msg_t * m = lv_event_get_msg(e);
        lv_obj_t * btn = lv_event_get_target(e);
        switch(lv_msg_get_id(m)) {
            case MSG_LOGIN_OK:
                lv_obj_clear_state(btn, LV_STATE_DISABLED);
                break;
            case MSG_LOG_OUT:
                lv_obj_add_state(btn, LV_STATE_DISABLED);
                break;
        }
    }
}

static void start_engine_msg_event_cb(lv_event_t * e)
{
    lv_msg_t * m = lv_event_get_msg(e);
    lv_obj_t * btn = lv_event_get_target(e);
    switch(lv_msg_get_id(m)) {
        case MSG_LOGIN_OK:
            lv_obj_clear_state(btn, LV_STATE_DISABLED);
            break;
        case MSG_LOG_OUT:
            lv_obj_add_state(btn, LV_STATE_DISABLED);
            break;
    }
}

static void info_label_msg_event_cb(lv_event_t * e)
{
    lv_obj_t * label = lv_event_get_target(e);
    lv_msg_t * m = lv_event_get_msg(e);
    switch(lv_msg_get_id(m)) {
        case MSG_LOGIN_ERROR:
            lv_label_set_text(label, lv_msg_get_payload(m));
            lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_RED), 0);
            break;
        case MSG_LOGIN_OK:
            lv_label_set_text(label, "Login successful");
            lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_GREEN), 0);
            break;
        case MSG_LOG_OUT:
            lv_label_set_text(label, "Logged out");
            lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_GREY), 0);
            break;
        default:
            break;
    }
}

#endif

MicroPython code  

 GitHub Simulator
from micropython import const

# Define a message ID
MSG_LOGIN_ATTEMPT = const(1)
MSG_LOG_OUT       = const(2)
MSG_LOGIN_ERROR   = const(3)
MSG_LOGIN_OK      = const(4)

# Define the object that will be sent as msg payload
class Message:
    def __init__(self, value):
        self.value = value
    def message(self):
        return self.value
        
def auth_manager(m,passwd):
    payload = m.get_payload()
    pin_act = payload.__cast__().message()
    # print("pin act: ",pin_act,end="")
    # print(", pin axpected: ",passwd)
    pin_expected = passwd
    if pin_act == pin_expected:
        lv.msg_send(MSG_LOGIN_OK, None)
    else:
        lv.msg_send(MSG_LOGIN_ERROR, Message("Incorrect PIN"))

def textarea_event_cb(e):
    ta = e.get_target()
    code = e.get_code()
    if code == lv.EVENT.READY:
        passwd = Message(ta.get_text())
        lv.msg_send(MSG_LOGIN_ATTEMPT, passwd)
    elif code == lv.EVENT.MSG_RECEIVED:
        m = e.get_msg()
        id = m.get_id()
        if id == MSG_LOGIN_ERROR:
            # If there was an error, clean the text area
            msg = m.get_payload().__cast__()
            if len(msg.message()):
                   ta.set_text("")
        elif id == MSG_LOGIN_OK:
            ta.add_state(lv.STATE.DISABLED)
            ta.clear_state(lv.STATE.FOCUSED | lv.STATE.FOCUS_KEY)
        elif id == MSG_LOG_OUT:
            ta.set_text("");
            ta.clear_state(lv.STATE.DISABLED)

def log_out_event_cb(e):
    code = e.get_code()
    if code == lv.EVENT.CLICKED:
        lv.msg_send(MSG_LOG_OUT, None)
    elif code == lv.EVENT.MSG_RECEIVED:
        m = e.get_msg()
        btn = e.get_target()
        id = m.get_id()
        if id == MSG_LOGIN_OK:
            btn.clear_state(lv.STATE.DISABLED)
        elif id == MSG_LOG_OUT:
            btn.add_state(lv.STATE.DISABLED)

def start_engine_msg_event_cb(e):

    m = e.get_msg()
    btn = e.get_target()
    id = m.get_id()
    if id == MSG_LOGIN_OK:
        btn.clear_state(lv.STATE.DISABLED)
    elif id == MSG_LOG_OUT:
        btn.add_state(lv.STATE.DISABLED)


def info_label_msg_event_cb(e):
    label = e.get_target()
    m = e.get_msg()
    id = m.get_id()
    if id ==  MSG_LOGIN_ERROR:
        payload = m.get_payload()
        label.set_text(payload.__cast__().message())
        label.set_style_text_color(lv.palette_main(lv.PALETTE.RED), 0)
    elif id == MSG_LOGIN_OK:
        label.set_text("Login successful")
        label.set_style_text_color(lv.palette_main(lv.PALETTE.GREEN), 0)
    elif id == MSG_LOG_OUT:
        label.set_text("Logged out")
        label.set_style_text_color(lv.palette_main(lv.PALETTE.GREY), 0)

def register_auth(msg_id,auth_msg):
    lv.msg_subscribe(MSG_LOGIN_ATTEMPT, lambda m: auth_msg(m,"hello"), None)
#
# Simple PIN login screen.
# No global variables are used, all state changes are communicated via messages.

register_auth(MSG_LOGIN_ATTEMPT,auth_manager)
# lv.msg_subscribe_obj(MSG_LOGIN_ATTEMPT, auth_manager, "Hello")

# Create a slider in the center of the display
ta = lv.textarea(lv.scr_act())
ta.set_pos(10, 10)
ta.set_width(200)
ta.set_one_line(True)
ta.set_password_mode(True)
ta.set_placeholder_text("The password is: hello")
ta.add_event_cb(textarea_event_cb, lv.EVENT.ALL, None)
lv.msg_subscribe_obj(MSG_LOGIN_ERROR, ta, None)
lv.msg_subscribe_obj(MSG_LOGIN_OK, ta, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, ta, None)

kb = lv.keyboard(lv.scr_act())
kb.set_textarea(ta)

# Create a log out button which will be active only when logged in
btn = lv.btn(lv.scr_act())
btn.set_pos(240, 10)
btn.add_event_cb(log_out_event_cb, lv.EVENT.ALL, None)
lv.msg_subscribe_obj(MSG_LOGIN_OK, btn, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, btn, None)

label = lv.label(btn);
label.set_text("LOG OUT")

# Create a label to show info
label = lv.label(lv.scr_act());
label.set_text("")
label.add_event_cb(info_label_msg_event_cb, lv.EVENT.MSG_RECEIVED, None)
label.set_pos(10, 60)
lv.msg_subscribe_obj(MSG_LOGIN_ERROR, label, None)
lv.msg_subscribe_obj(MSG_LOGIN_OK, label, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, label, None)

#Create button which will be active only when logged in
btn = lv.btn(lv.scr_act())
btn.set_pos(10, 80)
btn.add_event_cb(start_engine_msg_event_cb, lv.EVENT.MSG_RECEIVED, None)
btn.add_flag(lv.obj.FLAG.CHECKABLE)
lv.msg_subscribe_obj(MSG_LOGIN_OK, btn, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, btn, None)

label = lv.label(btn)
label.set_text("START ENGINE")

lv.msg_send(MSG_LOG_OUT, None)


Setting the same value from many sources

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES

static int32_t limit_value(int32_t v);
static void btn_event_cb(lv_event_t * e);
static void label_event_cb(lv_event_t * e);
static void slider_event_cb(lv_event_t * e);

static int32_t power_value;

/**
 * Show how an increment button, a decrement button, as slider can set a value
 * and a label display it.
 * The current value (i.e. the system's state) is stored only in one static variable in a function
 * and no global variables are required.
 */
void lv_example_msg_3(void)
{

    lv_obj_t * panel = lv_obj_create(lv_scr_act());
    lv_obj_set_size(panel, 250, LV_SIZE_CONTENT);
    lv_obj_center(panel);
    lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(panel, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START);

    lv_obj_t * btn;
    lv_obj_t * label;

    /*Up button*/
    btn = lv_btn_create(panel);
    lv_obj_set_flex_grow(btn, 1);
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
    label = lv_label_create(btn);
    lv_label_set_text(label, LV_SYMBOL_LEFT);
    lv_obj_center(label);

    /*Current value*/
    label = lv_label_create(panel);
    lv_obj_set_flex_grow(label, 2);
    lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
    lv_label_set_text(label, "?");
    lv_msg_subscribe_obj((lv_msg_id_t)&power_value, label, NULL);
    lv_obj_add_event_cb(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);

    /*Down button*/
    btn = lv_btn_create(panel);
    lv_obj_set_flex_grow(btn, 1);
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
    label = lv_label_create(btn);
    lv_label_set_text(label, LV_SYMBOL_RIGHT);
    lv_obj_center(label);

    /*Slider*/
    lv_obj_t * slider = lv_slider_create(panel);
    lv_obj_set_flex_grow(slider, 1);
    lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
    lv_msg_subscribe_obj((lv_msg_id_t)&power_value, slider, NULL);
    lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_ALL, NULL);

    power_value = 30;
    lv_msg_update_value(&power_value);
}

static int32_t limit_value(int32_t v)
{
    return LV_CLAMP(30, v, 80);
}


static void btn_event_cb(lv_event_t * e)
{
    lv_obj_t * btn = lv_event_get_target(e);
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_CLICKED || code == LV_EVENT_LONG_PRESSED_REPEAT) {
        if(lv_obj_get_index(btn) == 0) {    /*First object is the dec. button*/
            power_value = limit_value(power_value - 1);
            lv_msg_update_value(&power_value);
        }
        else {
            power_value = limit_value(power_value + 1);
            lv_msg_update_value(&power_value);
        }
    }
}

static void label_event_cb(lv_event_t * e)
{
    lv_obj_t * label = lv_event_get_target(e);
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_MSG_RECEIVED) {
        lv_msg_t * m = lv_event_get_msg(e);
        const int32_t * v = lv_msg_get_payload(m);
        lv_label_set_text_fmt(label, "%"LV_PRId32" %%", *v);
    }
}

static void slider_event_cb(lv_event_t * e)
{
    lv_obj_t * slider = lv_event_get_target(e);
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_VALUE_CHANGED) {
        power_value = limit_value(lv_slider_get_value(slider));
        lv_msg_update_value(&power_value);
    }
    else if(code == LV_EVENT_MSG_RECEIVED) {
        lv_msg_t * m = lv_event_get_msg(e);
        const int32_t * v = lv_msg_get_payload(m);
        lv_slider_set_value(slider, *v, LV_ANIM_OFF);
    }
}

#endif

MicroPython code  

 GitHub Simulator
# Define a message ID
MSG_INC            = 1
MSG_DEC            = 2
MSG_SET            = 3
MSG_UPDATE         = 4
MSG_UPDATE_REQUEST = 5

# Define the object that will be sent as msg payload
class NewValue:
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return f"{self.value} %"
class LV_Example_Msg_2:
    
    def __init__(self):
        self.value = 10
        lv.msg_subscribe(MSG_INC, self.value_handler, None)
        lv.msg_subscribe(MSG_DEC, self.value_handler, None)
        lv.msg_subscribe(MSG_SET, self.value_handler, None)
        lv.msg_subscribe(MSG_UPDATE, self.value_handler, None)
        lv.msg_subscribe(MSG_UPDATE_REQUEST, self.value_handler, None)

        panel = lv.obj(lv.scr_act())
        panel.set_size(250, lv.SIZE_CONTENT)
        panel.center()
        panel.set_flex_flow(lv.FLEX_FLOW.ROW)
        panel.set_flex_align(lv.FLEX_ALIGN.SPACE_BETWEEN, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START)

        # Up button
        btn = lv.btn(panel)
        btn.set_flex_grow(1)
        btn.add_event_cb(self.btn_event_cb, lv.EVENT.ALL, None)
        label = lv.label(btn)
        label.set_text(lv.SYMBOL.LEFT)
        label.center()
        
        # Current value
        label = lv.label(panel)
        label.set_flex_grow(2)
        label.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0)
        label.set_text("?")
        lv.msg_subscribe_obj(MSG_UPDATE, label, None)
        label.add_event_cb(self.label_event_cb, lv.EVENT.MSG_RECEIVED, None)
        
        # Down button
        btn = lv.btn(panel)
        btn.set_flex_grow(1)
        btn.add_event_cb(self.btn_event_cb, lv.EVENT.ALL, None)
        label = lv.label(btn)
        label.set_text(lv.SYMBOL.RIGHT)
        label.center()
        
        # Slider
        slider = lv.slider(panel)
        slider.set_flex_grow(1)
        slider.add_flag(lv.OBJ_FLAG_FLEX_IN_NEW_TRACK)
        slider.add_event_cb(self.slider_event_cb, lv.EVENT.ALL, None)
        lv.msg_subscribe_obj(MSG_UPDATE, slider, None)
        
        
        # As there are new UI elements that don't know the system's state
        # send an UPDATE REQUEST message which will trigger an UPDATE message with the current value
        lv.msg_send(MSG_UPDATE_REQUEST, None)
        
    def value_handler(self,m):
        old_value = self.value
        id = m.get_id()
        if id == MSG_INC:
            if self.value < 100:
                self.value +=1
        elif id == MSG_DEC:
            if self.value > 0:
                self.value -=1
        elif id == MSG_SET:
            payload = m.get_payload()
            new_value=payload.__cast__()
            self.value = new_value.value
            # print("value_handler: new value: {:d}".format(new_value.value)) 
        elif id == MSG_UPDATE_REQUEST:
            lv.msg_send(MSG_UPDATE, NewValue(self.value))
         
        if self.value != old_value: 
                lv.msg_send(MSG_UPDATE, NewValue(self.value));
            
    def btn_event_cb(self,e):
        btn = e.get_target()
        code = e.get_code()
        if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
            if btn.get_index() == 0:      # rst object is the dec. button
                lv.msg_send(MSG_DEC, None)
            else :
                lv.msg_send(MSG_INC, None)

    def label_event_cb(self,e):
        label = e.get_target()
        code = e.get_code()
        if code == lv.EVENT.MSG_RECEIVED:
            m = e.get_msg()
            if m.get_id() == MSG_UPDATE:
                payload = m.get_payload()
                value=payload.__cast__()
                # print("label_event_cb: " + str(value))
                label.set_text(str(value))

    def slider_event_cb(self,e):
        slider = e.get_target()
        code = e.get_code()
        if code == lv.EVENT.VALUE_CHANGED:
            v = slider.get_value()
            # print("slider_event_cb: {:d}".format(v))
            lv.msg_send(MSG_SET, NewValue(v))
        
        elif code == lv.EVENT.MSG_RECEIVED:
            m = e.get_msg()
            if m.get_id() == MSG_UPDATE:
                v = m.get_payload()
                value = v.__cast__()
                slider.set_value(value.value, lv.ANIM.OFF)

lv_example_msg_2 = LV_Example_Msg_2()


API

Typedefs

typedef lv_uintptr_t lv_msg_id_t
typedef void (*lv_msg_subscribe_cb_t)(lv_msg_t *msg)

Functions

void lv_msg_init(void)

Called internally to initialize the message module

void *lv_msg_subscribe(lv_msg_id_t msg_id, lv_msg_subscribe_cb_t cb, void *user_data)

Subscribe to an msg_id

Parameters
  • msg_id -- the message ID to listen to

  • cb -- callback to call if a message with msg_id was sent

  • user_data -- arbitrary data which will be available in cb too

Returns

pointer to a "subscribe object". It can be used the unsubscribe.

void *lv_msg_subscribe_obj(lv_msg_id_t msg_id, lv_obj_t *obj, void *user_data)

Subscribe an lv_obj to a message. LV_EVENT_MSG_RECEIVED will be triggered if a message with matching ID was sent

Parameters
  • msg_id -- the message ID to listen to

  • obj -- pointer to an lv_obj

  • user_data -- arbitrary data which will be available in cb too

Returns

pointer to a "subscribe object". It can be used the unsubscribe.

void lv_msg_unsubscribe(void *s)

Cancel a previous subscription

Parameters

s -- pointer to a "subscibe object". Return value of lv_msg_subscribe or lv_msg_subscribe_obj

void lv_msg_send(lv_msg_id_t msg_id, const void *payload)

Send a message with a given ID and payload

Parameters
  • msg_id -- ID of the message to send

  • data -- pointer to the data to send

void lv_msg_update_value(void *v)

Send a message where the message ID is v (the value of the pointer) and the payload is v. It can be used to send unique messages when a variable changed.

Note

to subscribe to a variable use lv_msg_subscribe((lv_msg_id_t)v, msg_cb, user_data) or lv_msg_subscribe_obj((lv_msg_id_t)v, obj, user_data)

Parameters

v -- pointer to a variable.

lv_msg_id_t lv_msg_get_id(lv_msg_t *m)

Get the ID of a message object. Typically used in the subscriber callback.

Parameters

m -- pointer to a message object

Returns

the ID of the message

const void *lv_msg_get_payload(lv_msg_t *m)

Get the payload of a message object. Typically used in the subscriber callback.

Parameters

m -- pointer to a message object

Returns

the payload of the message

void *lv_msg_get_user_data(lv_msg_t *m)

Get the user data of a message object. Typically used in the subscriber callback.

Parameters

m -- pointer to a message object

Returns

the user data of the message

lv_msg_t *lv_event_get_msg(lv_event_t *e)

Get the message object from an event object. Can be used in LV_EVENT_MSG_RECEIVED events.

Parameters

e -- pointer to an event object

Returns

the message object or NULL if called with unrelated event code.

struct lv_msg_t

Public Members

lv_msg_id_t id
void *user_data
void *_priv_data
const void *payload