chore(gdb): add LVAnim wrapper with print_info, print_entries and dump anims command

This commit is contained in:
Benign X
2026-03-06 00:11:16 +08:00
committed by VIFEX
parent ded2b49dbd
commit 372b39a422
8 changed files with 216 additions and 2 deletions
+2
View File
@@ -34,6 +34,7 @@ from .lvgl import (
LVEventList, LVEventList,
event_code_name, event_code_name,
EVENT_CODE_NAMES, EVENT_CODE_NAMES,
LVAnim,
) )
from . import cmds as cmds from . import cmds as cmds
@@ -71,4 +72,5 @@ __all__ = [
"LVEventList", "LVEventList",
"event_code_name", "event_code_name",
"EVENT_CODE_NAMES", "EVENT_CODE_NAMES",
"LVAnim",
] ]
+8 -1
View File
@@ -2,8 +2,14 @@ import gdb
from .core import DumpObj from .core import DumpObj
from .display import DumpDisplayBuf from .display import DumpDisplayBuf
from .misc import InfoStyle, DumpCache, CheckPrefix, CheckCache
from .draw import InfoDrawUnit, DumpDrawTask from .draw import InfoDrawUnit, DumpDrawTask
from .misc import (
InfoStyle,
DumpCache,
CheckPrefix,
CheckCache,
DumpAnim,
)
from .debugger import Debugger from .debugger import Debugger
from .drivers import Lvglobal from .drivers import Lvglobal
@@ -25,6 +31,7 @@ DumpDisplayBuf()
DumpCache() DumpCache()
CheckPrefix() CheckPrefix()
CheckCache() CheckCache()
DumpAnim()
DumpDrawTask() DumpDrawTask()
# Infos # Infos
+8 -1
View File
@@ -1,4 +1,11 @@
from .lv_style import InfoStyle from .lv_style import InfoStyle
from .lv_cache import DumpCache, CheckPrefix, CheckCache from .lv_cache import DumpCache, CheckPrefix, CheckCache
from .lv_anim import DumpAnim
__all__ = ["InfoStyle", "DumpCache", "CheckPrefix", "CheckCache"] __all__ = [
"InfoStyle",
"DumpCache",
"CheckPrefix",
"CheckCache",
"DumpAnim",
]
+31
View File
@@ -0,0 +1,31 @@
import gdb
from lvglgdb.lvgl import curr_inst
from lvglgdb.lvgl.misc.lv_anim import LVAnim
class DumpAnim(gdb.Command):
"""dump all active animations
Usage:
dump anims - list all animations in a table
dump anims --detail - print detailed info for each animation
"""
def __init__(self):
super(DumpAnim, self).__init__(
"dump anims", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION
)
def invoke(self, args, from_tty):
anims = list(curr_inst().anims())
if not anims:
print("No active animations.")
return
if args.strip() == "--detail":
for anim in anims:
anim.print_info()
print()
else:
LVAnim.print_entries(anims)
+2
View File
@@ -35,6 +35,7 @@ from .misc import (
LVEventList, LVEventList,
event_code_name, event_code_name,
EVENT_CODE_NAMES, EVENT_CODE_NAMES,
LVAnim,
) )
__all__ = [ __all__ = [
@@ -76,4 +77,5 @@ __all__ = [
"LVEventList", "LVEventList",
"event_code_name", "event_code_name",
"EVENT_CODE_NAMES", "EVENT_CODE_NAMES",
"LVAnim",
] ]
@@ -61,6 +61,12 @@ class LVGL:
return LVImageCache(self.lv_global.img_cache) return LVImageCache(self.lv_global.img_cache)
def anims(self):
from ..misc.lv_anim import LVAnim
for anim in LVList(self.lv_global.anim_state.anim_ll, "lv_anim_t"):
yield LVAnim(anim)
def image_header_cache(self): def image_header_cache(self):
from ..misc.lv_image_header_cache import LVImageHeaderCache from ..misc.lv_image_header_cache import LVImageHeaderCache
@@ -23,6 +23,7 @@ from .lv_event import (
event_code_name, event_code_name,
EVENT_CODE_NAMES, EVENT_CODE_NAMES,
) )
from .lv_anim import LVAnim
__all__ = [ __all__ = [
"LVList", "LVList",
@@ -51,4 +52,5 @@ __all__ = [
"LVEventList", "LVEventList",
"event_code_name", "event_code_name",
"EVENT_CODE_NAMES", "EVENT_CODE_NAMES",
"LVAnim",
] ]
+157
View File
@@ -0,0 +1,157 @@
from prettytable import PrettyTable
from lvglgdb.value import Value, ValueInput
def _fmt_cb(cb: Value) -> str:
"""Format a callback pointer as symbol or hex."""
addr = int(cb)
if not addr:
return "-"
return cb.format_string(symbols=True, address=True)
class LVAnim(Value):
"""LVGL animation wrapper"""
def __init__(self, anim: ValueInput):
super().__init__(Value.normalize(anim, "lv_anim_t"))
@property
def var(self) -> Value:
return self.super_value("var")
@property
def exec_cb(self) -> Value:
return self.super_value("exec_cb")
@property
def start_cb(self) -> Value:
return self.super_value("start_cb")
@property
def completed_cb(self) -> Value:
return self.super_value("completed_cb")
@property
def deleted_cb(self) -> Value:
return self.super_value("deleted_cb")
@property
def path_cb(self) -> Value:
return self.super_value("path_cb")
@property
def user_data(self) -> Value:
return self.super_value("user_data")
@property
def start_value(self) -> int:
return int(self.super_value("start_value"))
@property
def current_value(self) -> int:
return int(self.super_value("current_value"))
@property
def end_value(self) -> int:
return int(self.super_value("end_value"))
@property
def duration(self) -> int:
return int(self.super_value("duration"))
@property
def act_time(self) -> int:
return int(self.super_value("act_time"))
@property
def reverse_duration(self) -> int:
return int(self.super_value("reverse_duration"))
@property
def reverse_delay(self) -> int:
return int(self.super_value("reverse_delay"))
@property
def repeat_delay(self) -> int:
return int(self.super_value("repeat_delay"))
@property
def repeat_cnt(self) -> int:
return int(self.super_value("repeat_cnt"))
@property
def is_paused(self) -> bool:
return bool(int(self.super_value("is_paused")))
@property
def reverse_play_in_progress(self) -> bool:
return bool(int(self.super_value("reverse_play_in_progress")))
@property
def early_apply(self) -> bool:
return bool(int(self.super_value("early_apply")))
def _status_str(self) -> str:
"""Short status string for table display."""
if self.is_paused:
return "paused"
if self.reverse_play_in_progress:
return "reverse"
return "running"
def print_info(self):
"""Print detailed info for a single animation."""
print(f"Animation @{hex(int(self.address))}")
print(f" var = {self.var}")
print(f" exec_cb = {_fmt_cb(self.exec_cb)}")
print(f" path_cb = {_fmt_cb(self.path_cb)}")
print(f" start_cb = {_fmt_cb(self.start_cb)}")
print(f" completed_cb = {_fmt_cb(self.completed_cb)}")
print(f" deleted_cb = {_fmt_cb(self.deleted_cb)}")
print(f" user_data = {self.user_data}")
print(f" value = {self.start_value} -> {self.current_value} -> {self.end_value}")
print(f" duration = {self.duration}ms act_time={self.act_time}ms")
repeat = "inf" if self.repeat_cnt == 0xFFFF else str(self.repeat_cnt)
print(f" repeat = {repeat} repeat_delay={self.repeat_delay}ms")
print(f" reverse = dur={self.reverse_duration}ms delay={self.reverse_delay}ms")
print(f" status = {self._status_str()} early_apply={self.early_apply}")
@staticmethod
def print_entries(anims):
"""Print animations as a PrettyTable."""
table = PrettyTable()
table.field_names = [
"#",
"var",
"exec_cb",
"value(start/cur/end)",
"duration",
"act_time",
"repeat",
"status",
]
table.align = "l"
for i, anim in enumerate(anims):
cb_str = _fmt_cb(anim.exec_cb)
repeat = "inf" if anim.repeat_cnt == 0xFFFF else str(anim.repeat_cnt)
value_str = f"{anim.start_value}/{anim.current_value}/{anim.end_value}"
table.add_row(
[
i,
anim.var,
cb_str,
value_str,
f"{anim.duration}ms",
f"{anim.act_time}ms",
repeat,
anim._status_str(),
]
)
if not table.rows:
print("No active animations.")
else:
print(table)