From b6ea5bbddf9db836ba206127b6eb77ca21cb8fa4 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 8 Aug 2020 09:58:44 +0200 Subject: Lua channel introspection (#68) --- backends/lua.c | 40 ++++++++++++++++++++++++++++++++++++++-- backends/lua.md | 5 +++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/backends/lua.c b/backends/lua.c index 98ce369..cf59f8f 100644 --- a/backends/lua.c +++ b/backends/lua.c @@ -137,6 +137,8 @@ static int lua_update_timerfd(){ } static void lua_thread_resume(size_t current_thread){ + int thread_status = 0; + //push coroutine reference lua_pushstring(thread[current_thread].thread, LUA_REGISTRY_CURRENT_THREAD); lua_pushnumber(thread[current_thread].thread, current_thread); @@ -144,9 +146,17 @@ static void lua_thread_resume(size_t current_thread){ //call thread main DBGPF("Resuming thread %" PRIsize_t " on %s", current_thread, thread[current_thread].instance->name); - if(lua_resume(thread[current_thread].thread, NULL, 0) != LUA_YIELD){ - DBGPF("Thread %" PRIsize_t " on %s terminated", current_thread, thread[current_thread].instance->name); + thread_status = lua_resume(thread[current_thread].thread, NULL, 0); + + if(thread_status == LUA_YIELD){ + DBGPF("Thread %" PRIsize_t " on %s yielded execution", current_thread, thread[current_thread].instance->name); + } + else{ thread[current_thread].timeout = 0; + LOGPF("Thread %" PRIsize_t " on %s terminated", current_thread, thread[current_thread].instance->name); + if(thread_status){ + LOGPF("Last error message: %s", lua_tostring(thread[current_thread].thread, -1)); + } } //remove coroutine reference @@ -166,6 +176,30 @@ static instance* lua_fetch_instance(lua_State* interpreter){ return inst; } +static int lua_callback_channels(lua_State* interpreter){ + size_t u; + instance* inst = lua_fetch_instance(interpreter); + lua_instance_data* data = (lua_instance_data*) inst->impl; + + if(!last_timestamp){ + LOG("The channels() API will not return usable results before the configuration has been read completely"); + } + + //create a table for the return array + lua_createtable(interpreter, data->channels, 0); + + for(u = 0; u < data->channels; u++){ + //push the key + lua_pushnumber(interpreter, u + 1); + //push the value + lua_pushstring(interpreter, data->channel[u].name); + //settable pops key and value, leaving the table + lua_settable(interpreter, -3); + } + + return 1; +} + static int lua_callback_thread(lua_State* interpreter){ instance* inst = lua_fetch_instance(interpreter); size_t u = threads; @@ -467,6 +501,7 @@ static int lua_instance(instance* inst){ lua_register(data->interpreter, "thread", lua_callback_thread); lua_register(data->interpreter, "sleep", lua_callback_sleep); lua_register(data->interpreter, "cleanup_handler", lua_callback_cleanup_handler); + lua_register(data->interpreter, "channels", lua_callback_channels); //store instance pointer to the lua state lua_pushstring(data->interpreter, LUA_REGISTRY_KEY); @@ -604,6 +639,7 @@ static int lua_resolve_symbol(lua_State* interpreter, char* symbol){ || !strcmp(symbol, "input_channel") || !strcmp(symbol, "timestamp") || !strcmp(symbol, "cleanup_handler") + || !strcmp(symbol, "channels") || !strcmp(symbol, "interval")){ return LUA_NOREF; } diff --git a/backends/lua.md b/backends/lua.md index b2f40e0..026c945 100644 --- a/backends/lua.md +++ b/backends/lua.md @@ -6,8 +6,8 @@ and manipulate events using the Lua scripting language. Every instance has its own interpreter state which can be loaded with custom scripts. To process incoming channel events, the MIDIMonster calls corresponding Lua functions (if they exist) -with the value (as a Lua `number` type) as parameter. Alternatively, a designated default channel handler -which will receive events for all incoming channels may be supplied in the configuration. +with the normalized event value (as a Lua `number` type) as parameter. Alternatively, a designated +default channel handler which will receive events for all incoming channels may be set in the configuration. The backend can also call Lua functions repeatedly using a timer, allowing users to implement time-based functionality (such as evaluating a fixed mathematical function or outputting periodic updates). @@ -25,6 +25,7 @@ The following functions are provided within the Lua interpreter for interaction | `timestamp()` | `print(timestamp())` | Returns the core timestamp for this iteration with millisecond resolution. This is not a performance timer, but intended for timeouting, etc | | `thread(function)` | `thread(run_show)` | Run a function as a Lua thread (see below) | | `sleep(number)` | `sleep(100)` | Suspend current thread for time specified in milliseconds | +| `channels()` | `chans = channels()` | Fetch an array of all currently known channels on the instance. Note that this function only works properly after the configuration has been read completely, i.e. any time after startup | While a channel handler executes, calling `input_value` for that channel returns the previous value. The stored value is updated once the handler returns. -- cgit v1.2.3