Fork of Tangara with customizations
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
tangara-fw/lib/luavgl/src/timer.c

222 lines
4.8 KiB

#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 */
}