diff --git a/scripts/gdb/lvglgdb/__init__.py b/scripts/gdb/lvglgdb/__init__.py index a840d2c94c..c11da65be5 100644 --- a/scripts/gdb/lvglgdb/__init__.py +++ b/scripts/gdb/lvglgdb/__init__.py @@ -38,6 +38,8 @@ from .lvgl import ( LVTimer, LVImageDecoder, LVFsDrv, + LVIndev, + INDEV_TYPE_NAMES, ) from . import cmds as cmds @@ -79,4 +81,6 @@ __all__ = [ "LVTimer", "LVImageDecoder", "LVFsDrv", + "LVIndev", + "INDEV_TYPE_NAMES", ] diff --git a/scripts/gdb/lvglgdb/cmds/__init__.py b/scripts/gdb/lvglgdb/cmds/__init__.py index 8625cada31..65a056115d 100644 --- a/scripts/gdb/lvglgdb/cmds/__init__.py +++ b/scripts/gdb/lvglgdb/cmds/__init__.py @@ -1,6 +1,6 @@ import gdb -from .core import DumpObj +from .core import DumpObj, DumpIndev from .display import DumpDisplayBuf from .draw import InfoDrawUnit, DumpDrawTask from .misc import ( @@ -38,6 +38,7 @@ DumpAnim() DumpTimer() DumpImageDecoder() DumpFsDrv() +DumpIndev() DumpDrawTask() # Infos diff --git a/scripts/gdb/lvglgdb/cmds/core/__init__.py b/scripts/gdb/lvglgdb/cmds/core/__init__.py index 854d087a70..b0cac928c0 100644 --- a/scripts/gdb/lvglgdb/cmds/core/__init__.py +++ b/scripts/gdb/lvglgdb/cmds/core/__init__.py @@ -1,5 +1,7 @@ from .lv_obj import DumpObj +from .lv_indev import DumpIndev __all__ = [ "DumpObj", + "DumpIndev", ] diff --git a/scripts/gdb/lvglgdb/cmds/core/lv_indev.py b/scripts/gdb/lvglgdb/cmds/core/lv_indev.py new file mode 100644 index 0000000000..a5d5a575c0 --- /dev/null +++ b/scripts/gdb/lvglgdb/cmds/core/lv_indev.py @@ -0,0 +1,16 @@ +import gdb + +from lvglgdb.lvgl import curr_inst +from lvglgdb.lvgl.core.lv_indev import LVIndev + + +class DumpIndev(gdb.Command): + """dump all input devices""" + + def __init__(self): + super(DumpIndev, self).__init__( + "dump indev", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION + ) + + def invoke(self, args, from_tty): + LVIndev.print_entries(curr_inst().indevs()) diff --git a/scripts/gdb/lvglgdb/lvgl/__init__.py b/scripts/gdb/lvglgdb/lvgl/__init__.py index a444431456..1e3a9ce19c 100644 --- a/scripts/gdb/lvglgdb/lvgl/__init__.py +++ b/scripts/gdb/lvglgdb/lvgl/__init__.py @@ -1,4 +1,12 @@ -from .core import LVObject, ObjStyle, curr_inst, dump_obj_info, dump_obj_styles +from .core import ( + LVObject, + ObjStyle, + curr_inst, + dump_obj_info, + dump_obj_styles, + LVIndev, + INDEV_TYPE_NAMES, +) from .display import LVDisplay from .draw import ( LVDrawBuf, @@ -84,4 +92,6 @@ __all__ = [ "LVTimer", "LVImageDecoder", "LVFsDrv", + "LVIndev", + "INDEV_TYPE_NAMES", ] diff --git a/scripts/gdb/lvglgdb/lvgl/core/__init__.py b/scripts/gdb/lvglgdb/lvgl/core/__init__.py index f57ae299bb..19d69b6301 100644 --- a/scripts/gdb/lvglgdb/lvgl/core/__init__.py +++ b/scripts/gdb/lvglgdb/lvgl/core/__init__.py @@ -1,5 +1,6 @@ from .lv_obj import LVObject, ObjStyle, dump_obj_info, dump_obj_styles from .lv_global import curr_inst +from .lv_indev import LVIndev, INDEV_TYPE_NAMES __all__ = [ "LVObject", @@ -7,4 +8,6 @@ __all__ = [ "curr_inst", "dump_obj_info", "dump_obj_styles", + "LVIndev", + "INDEV_TYPE_NAMES", ] diff --git a/scripts/gdb/lvglgdb/lvgl/core/lv_global.py b/scripts/gdb/lvglgdb/lvgl/core/lv_global.py index 268665e6a9..b224d7682d 100644 --- a/scripts/gdb/lvglgdb/lvgl/core/lv_global.py +++ b/scripts/gdb/lvglgdb/lvgl/core/lv_global.py @@ -73,6 +73,12 @@ class LVGL: for timer in LVList(self.lv_global.timer_state.timer_ll, "lv_timer_t"): yield LVTimer(timer) + def indevs(self): + from .lv_indev import LVIndev + + for indev in LVList(self.lv_global.indev_ll, "lv_indev_t"): + yield LVIndev(indev) + def image_decoders(self): from ..misc.lv_image_decoder import LVImageDecoder diff --git a/scripts/gdb/lvglgdb/lvgl/core/lv_indev.py b/scripts/gdb/lvglgdb/lvgl/core/lv_indev.py new file mode 100644 index 0000000000..600410f4f8 --- /dev/null +++ b/scripts/gdb/lvglgdb/lvgl/core/lv_indev.py @@ -0,0 +1,109 @@ +from prettytable import PrettyTable + +from lvglgdb.value import Value, ValueInput +from .lv_indev_consts import INDEV_TYPE_NAMES + + +class LVIndev(Value): + """LVGL input device wrapper""" + + def __init__(self, indev: ValueInput): + super().__init__(Value.normalize(indev, "lv_indev_t")) + + @property + def type(self) -> int: + return int(self.super_value("type")) + + @property + def type_name(self) -> str: + return INDEV_TYPE_NAMES.get(self.type, f"UNKNOWN({self.type})") + + @property + def state(self) -> int: + return int(self.super_value("state")) + + @property + def enabled(self) -> bool: + return bool(int(self.super_value("enabled"))) + + @property + def long_press_time(self) -> int: + return int(self.super_value("long_press_time")) + + @property + def scroll_limit(self) -> int: + return int(self.super_value("scroll_limit")) + + @property + def scroll_throw(self) -> int: + return int(self.super_value("scroll_throw")) + + @property + def long_press_repeat_time(self) -> int: + return int(self.super_value("long_press_repeat_time")) + + @property + def read_cb(self) -> Value: + return self.super_value("read_cb") + + @property + def read_timer(self) -> Value: + return self.super_value("read_timer") + + @property + def disp(self) -> Value: + return self.super_value("disp") + + @property + def group(self) -> Value: + return self.super_value("group") + + @property + def cursor(self) -> Value: + return self.super_value("cursor") + + @property + def user_data(self) -> Value: + return self.super_value("user_data") + + @property + def driver_data(self) -> Value: + return self.super_value("driver_data") + + @staticmethod + def print_entries(indevs): + """Print input devices as a PrettyTable.""" + table = PrettyTable() + table.field_names = [ + "#", + "type", + "enabled", + "state", + "read_cb", + "long_press_time", + "scroll_limit", + "group", + ] + table.align = "l" + + for i, indev in enumerate(indevs): + cb_str = indev.read_cb.format_string(symbols=True) + grp = int(indev.group) + grp_str = f"0x{grp:x}" if grp else "-" + table.add_row( + [ + i, + indev.type_name, + indev.enabled, + indev.state, + cb_str, + indev.long_press_time, + indev.scroll_limit, + grp_str, + ] + ) + + if not table.rows: + print("No input devices.") + else: + print(table) diff --git a/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py b/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py new file mode 100644 index 0000000000..0501354dea --- /dev/null +++ b/scripts/gdb/lvglgdb/lvgl/core/lv_indev_consts.py @@ -0,0 +1,14 @@ +""" +Auto-generated indev constants from LVGL headers. + +Do not edit manually. Regenerate with: + python3 scripts/gen_indev_consts.py +""" + +INDEV_TYPE_NAMES = { + 0: "NONE", + 1: "POINTER", + 2: "KEYPAD", + 3: "BUTTON", + 4: "ENCODER", +} diff --git a/scripts/gdb/scripts/gen_indev_consts.py b/scripts/gdb/scripts/gen_indev_consts.py new file mode 100644 index 0000000000..f33f7dc0c4 --- /dev/null +++ b/scripts/gdb/scripts/gen_indev_consts.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +""" +Generate indev constant tables from LVGL header files. + +Parses lv_indev.h for indev type enum. + +Usage: + python3 scripts/gen_indev_consts.py +""" + +import re +from pathlib import Path + +SCRIPT_DIR = Path(__file__).parent +GDB_ROOT = SCRIPT_DIR.parent +LVGL_SRC = GDB_ROOT.parent.parent / "src" +OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "core" / "lv_indev_consts.py" + +INDEV_H = LVGL_SRC / "indev" / "lv_indev.h" + + +def parse_enum(path: Path, enum_type: str, prefix: str) -> dict[int, str]: + """Parse a C enum from a header file.""" + text = path.read_text() + + pattern = rf"\}}\s*{re.escape(enum_type)}\s*;" + m = re.search(rf"typedef\s+enum\s*\{{(.*?){pattern}", text, re.DOTALL) + if not m: + raise RuntimeError(f"Cannot find {enum_type} enum in {path}") + + entries = {} + current_val = 0 + for line in m.group(1).splitlines(): + line = line.strip().rstrip(",") + if ( + not line + or line.startswith("/*") + or line.startswith("//") + or line.startswith("*") + or line.startswith("#") + ): + continue + + match = re.match(rf"({re.escape(prefix)}\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line) + if match: + name = match.group(1) + current_val = int(match.group(2), 0) + else: + match = re.match(rf"({re.escape(prefix)}\w+)", line) + if not match: + continue + name = match.group(1) + + short = name.removeprefix(prefix) + entries[current_val] = short + current_val += 1 + + return entries + + +def generate(indev_types: dict[int, str]) -> str: + """Generate Python source for the indev constants module.""" + lines = [ + '"""', + "Auto-generated indev constants from LVGL headers.", + "", + "Do not edit manually. Regenerate with:", + " python3 scripts/gen_indev_consts.py", + '"""', + "", + "INDEV_TYPE_NAMES = {", + ] + for k in sorted(indev_types): + lines.append(f' {k}: "{indev_types[k]}",') + lines.append("}") + lines.append("") + + return "\n".join(lines) + + +def main(): + indev_types = parse_enum(INDEV_H, "lv_indev_type_t", "LV_INDEV_TYPE_") + src = generate(indev_types) + OUTPUT.write_text(src) + print(f"Generated {OUTPUT} ({len(indev_types)} indev types)") + + +if __name__ == "__main__": + main()