diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-11-12 19:14:09 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-11-12 19:14:09 +1100 |
| commit | 8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de (patch) | |
| tree | 02b6cf23f591915747ec2994381854a79979c4a0 /lib/luavgl/src/timer.c | |
| parent | 8471046a95ab9e00f7d42b56dbbc9ce3e5b424b9 (diff) | |
| download | tangara-fw-8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de.tar.gz | |
Convert the main menu screen to lua lol
Diffstat (limited to 'lib/luavgl/src/timer.c')
| -rw-r--r-- | lib/luavgl/src/timer.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/lib/luavgl/src/timer.c b/lib/luavgl/src/timer.c new file mode 100644 index 00000000..4ee334ca --- /dev/null +++ b/lib/luavgl/src/timer.c @@ -0,0 +1,222 @@ +#include "luavgl.h" +#include "private.h" + +typedef struct luavgl_timer_s { + lua_State *L; + int ref; /* ref to callback */ +} luavgl_timer_t; + +static lv_timer_t *luavgl_check_timer(lua_State *L, int index) +{ + lv_timer_t *v = *(lv_timer_t **)luaL_checkudata(L, index, "lv_timer"); + return v; +} + +static void luavgl_timer_cb(lv_timer_t *t) +{ + luavgl_timer_t *data = t->user_data; + lua_State *L = data->L; + int ref = data->ref; + if (ref == LUA_NOREF) { + return; + } + + int top = lua_gettop(L); + /* stack: 1. function, 2. timer userdata */ + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + lua_pushlightuserdata(L, t); + lua_rawget(L, LUA_REGISTRYINDEX); /* this should not fail*/ + + luavgl_pcall_int(L, 1, 0); + lua_settop(L, top); +} + +static void luavgl_timer_set_cb(void *_t, lua_State *L) +{ + lv_timer_t *t = _t; + int ref = luavgl_check_continuation(L, -1); + luavgl_timer_t *data = t->user_data; + + if (data->ref != LUA_NOREF) { + luaL_unref(L, LUA_REGISTRYINDEX, data->ref); + } + data->ref = ref; +} + +static void luavgl_timer_set_paused(lv_timer_t *t, int paused) +{ + /* pause or resume. */ + paused ? lv_timer_pause(t) : lv_timer_resume(t); +} + +/* clang-format off */ +static const luavgl_value_setter_t timer_property_table[] = { + { "paused", 0, { .setter = (setter_int_t)luavgl_timer_set_paused } }, + { "period", 0, { .setter = (setter_int_t)lv_timer_set_period } }, + { "repeat_count", 0, { .setter = (setter_int_t)lv_timer_set_repeat_count } }, + { "cb", SETTER_TYPE_STACK, { .setter_stack = luavgl_timer_set_cb } }, +}; + +/* clang-format on */ + +static int timer_set_para_cb(lua_State *L, void *data) +{ + int ret = luavgl_set_property(L, data, timer_property_table); + + if (ret != 0) { + debug("failed\n"); + } + + return ret; +} + +/* setup timer using parameter in table idx */ +int luavgl_timer_setup(lua_State *L, int idx, lv_timer_t *t) +{ + luavgl_iterate(L, idx, timer_set_para_cb, t); + return 1; +} + +/** + * t = luavgl:timer({timer parameters}) + * t:pause() + * t:resume() + * t:ready() -- make it ready right now + * + */ +static int luavgl_timer_create(lua_State *L) +{ + luavgl_timer_t *data = malloc(sizeof(luavgl_timer_t)); + if (data == NULL) { + return luaL_error(L, "No memory."); + } + data->ref = LUA_NOREF; + data->L = L; + + lv_timer_t *t = lv_timer_create(luavgl_timer_cb, 0, data); + + *(void **)lua_newuserdata(L, sizeof(void *)) = t; + luaL_getmetatable(L, "lv_timer"); + lua_setmetatable(L, -2); + + lua_pushlightuserdata(L, t); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* parameter table is on stack[1] */ + luavgl_timer_setup(L, 1, t); + lua_remove(L, 1); /* remove it to keep stack balance */ + + if (t->period == 0) { + /* if period is not set, then it's paused. */ + lv_timer_pause(t); + } + + return 1; +} + +static int luavgl_timer_set(lua_State *L) +{ + lv_timer_t *t = luavgl_check_timer(L, 1); + if (t == NULL) { + return luaL_argerror(L, 1, "timer is null."); + } + + luavgl_timer_setup(L, 2, t); + return 0; +} + +static int luavgl_timer_ready(lua_State *L) +{ + lv_timer_t *t = luavgl_check_timer(L, 1); + if (t == NULL) { + return luaL_argerror(L, 1, "timer is null."); + } + + lv_timer_ready(t); + return 0; +} + +static int luavgl_timer_resume(lua_State *L) +{ + lv_timer_t *t = luavgl_check_timer(L, 1); + if (t == NULL) { + return luaL_argerror(L, 1, "timer is null."); + } + + lv_timer_resume(t); + return 0; +} + +static int luavgl_timer_pause(lua_State *L) +{ + lv_timer_t *t = luavgl_check_timer(L, 1); + if (t == NULL) { + return luaL_argerror(L, 1, "timer is null."); + } + + lv_timer_pause(t); + + return 0; +} + +/* remove timer from obj, */ +static int luavgl_timer_delete(lua_State *L) +{ + lv_timer_t *t = luavgl_check_timer(L, 1); + if (t == NULL) { + return luaL_argerror(L, 1, "timer is null."); + } + + luavgl_timer_t *data = t->user_data; + if (data->ref) { + luaL_unref(L, LUA_REGISTRYINDEX, data->ref); + data->ref = LUA_NOREF; + } + + lua_pushlightuserdata(L, t); + lua_pushnil(L); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* we can only release memory in gc, since we need t->use_data */ + lv_timer_pause(t); + + debug("delete timer:%p\n", t); + return 0; +} + +static int luavgl_timer_gc(lua_State *L) +{ + /* stop timer if not stopped. */ + luavgl_timer_delete(L); + + lv_timer_t *t = luavgl_check_timer(L, 1); + free(t->user_data); + lv_timer_del(t); + + debug("gc timer:%p\n", t); + return 0; +} + +static const luaL_Reg luavgl_timer_methods[] = { + {"set", luavgl_timer_set }, + {"pause", luavgl_timer_pause }, + {"resume", luavgl_timer_resume}, + {"delete", luavgl_timer_delete}, + {"ready", luavgl_timer_ready }, + + {NULL, NULL } +}; + +static void luavgl_timer_init(lua_State *L) +{ + luaL_newmetatable(L, "lv_timer"); + + lua_pushcfunction(L, luavgl_timer_gc); + lua_setfield(L, -2, "__gc"); + + luaL_newlib(L, luavgl_timer_methods); /* methods belong to this type */ + lua_setfield(L, -2, "__index"); + + lua_pop(L, 1); /* pop __index table */ +} |
