Missing indev_drv_init()

Hi,

i try to follow some examples to learn lvgl for mpy. At the moment i’m trying the code from https://github.com/lvgl/lv_micropython

There you can find the snippet

import lvgl as lv

...

indev_drv = lv.indev_drv_t()
lv.indev_drv_init(indev_drv)

But lvgl hast no method indev_drv_init? Are there any changes or do i sth. wrong?

Thank you

If you are looking at the master branch of lv_micropython - it’s aligned to LVGL v7.
LVGL master branch is in fact LVGL v8 which was not released yet.
dev-v8 branch of lv_micropython is aligned to LVGL master branch.

Sure it has:

I think what @Lebowski is saying is that he’s missing access to that function in Python. I am experiencing the exact same problem. I’d love to contribute board files for M5Stack Core2 in pure Python.

If I look at driver/generic/lvindev_example.py, it seems to show how to register an indev driver from Python. But when my code does lv.indev_drv_register(indev_drv) I get AttributeError: 'module' object has no attribute 'indev_drv_init'. It looks like the python module lv does not implement the functions from lv_hal_indev.h. Here’s everything that starts with indev in lv:

indev_data_t    indev_drv_t     indev_get_act
indev_get_obj_act               indev_get_read_task
indev_proc_t    indev_proc_types_keypad_t
indev_proc_types_pointer_t      indev_proc_types_t
indev_search_obj                indev_t

That does leave stuff missing, no?

Ah, solved it!

Turns out the example at driver/generic/lvindev_example.py is all wrong, possibly describing a previous API. One does not need ‘modlvindev’ anymore, and the convention for the callback is a little different than is documented. The callback gets two arguments: a pointer to the lv_indev_drv_t that you initialised with and a pointer to the lv_indev_data_t that holds the coordinates.

The README at the lv_binding_micropython GitHub Repo used the current API when they show using the SDL mouse driver:

# Register SDL mouse driver

indev_drv = lv.indev_drv_t()
indev_drv.init() 
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = SDL.mouse_read
indev_drv.register()

But then you still have to work out how the callback is called, which can be gleaned from the source. Clearly documentation is lacking here, and the included example is flat-out wrong. I’ll file an issue.

To see how it’s done: below is a complete, working, freshly-tested driver for the FT6X36 touch IC:

import lvgl as lv
from machine import I2C, Pin

class ft6x36:

    def __init__(self, i2c_dev=0, sda=21, scl=22, addr=0x38, size_x=320, size_y=280, inv_x=False, inv_y=False, swap_xy=False):
        self.size_x, self.size_y = size_x, size_y
        self.inv_x, self.inv_y, self.swap_xy = inv_x, inv_y, swap_xy
        self.i2c = I2C(i2c_dev, sda=Pin(sda), scl=Pin(scl))
        self.addr = addr
        self.point = lv.point_t( {'x': 0, 'y': 0} )
        self.state = lv.INDEV_STATE.REL
        indev_drv = lv.indev_drv_t()
        indev_drv.init()
        indev_drv.type = lv.INDEV_TYPE.POINTER
        indev_drv.read_cb = self.callback
        indev_drv.register()

    def callback(self, driverptr, dataptr):
        sensorbytes = self.i2c.readfrom_mem(self.addr, 2, 5)
        points = sensorbytes[0]
        x = (sensorbytes[1] << 8 | sensorbytes[2]) & 0x0fff
        y = (sensorbytes[3] << 8 | sensorbytes[4]) & 0x0fff
        if x < self.size_x and y < self.size_y:
            x = size_x - x - 1 if self.inv_x else x
            y = size_y - y - 1 if self.inv_y else y
            (x, y) = (y, x) if self.swap_xy else (x, y)
            if points == 1 or points == 2:
                self.point = {'x': x, 'y': y}
                self.state = lv.INDEV_STATE.PR
            elif points == 0:
                self.state = lv.INDEV_STATE.REL
        data = lv.indev_data_t.cast(dataptr)
        data.point = self.point
        data.state = self.state
        return False

 

On my M5Stack Core2, the following gives me a pressable button:

import lvgl as lv
from ili9XXX import ili9341
from ft6x36 import ft6x36

disp = ili9341(mosi=23, miso=38, clk=18, dc=15, cs=5, invert=True, rot=0x10)
touch = ft6x36()

scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")

# Load the screen

lv.scr_load(scr)

Update: I filed a Pull Request to replace the broken example with one that works.

Update2: I submitted a modified (better) version of the FT6X36 driver as a Pull Request. You might want to use that instead of the preliminary version in this post… It does multi-touch (even when LVGL doesn’t do multi-touch, you can still read the second touch) and it checks whether it sees the touch IC at startup.

That’s true.
I think it goes back to v6.
On v7 and dev-v8 branches modlvindev is not needed and this example is obsolete.

Another example for indev driver is the evdev mouse device for Linux: