From 302d4bfcc49c69ea8251e1755ba3876555f680aa Mon Sep 17 00:00:00 2001 From: fulup Date: Wed, 9 Aug 2017 18:53:17 +0200 Subject: Not Working LUA user_data --- Controler-afb/ctl-lua.c | 354 +++++++++++++++++++++++++++++++++-------- data/helloworld-lua-script.lua | 2 +- data/onload-control-script.lua | 56 ++++++- nbproject/configurations.xml | 7 + 4 files changed, 342 insertions(+), 77 deletions(-) diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c index 0e44bc9..59ffbe8 100644 --- a/Controler-afb/ctl-lua.c +++ b/Controler-afb/ctl-lua.c @@ -16,6 +16,7 @@ * ref: * http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call * http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/ + * https://john.nachtimwald.com/2014/07/12/wrapping-a-c-library-in-lua/ */ #define _GNU_SOURCE @@ -39,6 +40,55 @@ typedef enum { LUA_DOSCRIPT, } LuaDoActionT; +#define CTX_MAGIC 123456789 +#define CTX_TOKEN "AFB_ctx" + +typedef struct { + int ctxMagic; + afb_req request; + char *info; +} LuaAfbContextT; + +typedef struct { + const char *callback; + const char *handle; +} LuaCallServiceT; + +typedef enum { + AFB_MSG_WARNING, + AFB_MSG_NOTICE, +} LuaAfbMessageT; + +STATIC LuaAfbContextT *LuaCtxCheck (lua_State *luaState, int index) { + LuaAfbContextT *afbContext; + luaL_checktype(luaState, index, LUA_TUSERDATA); + afbContext = (LuaAfbContextT *)luaL_checkudata(luaState, index, CTX_TOKEN); + if (afbContext == NULL && afbContext->ctxMagic != CTX_MAGIC) { + luaL_error(luaState, "Fail to retrieve user data context=%s", CTX_TOKEN); + AFB_ERROR ("afbContextCheck error retrieving afbContext"); + return NULL; + } + return afbContext; +} + +STATIC LuaAfbContextT *LuaCtxPush (lua_State *luaState, afb_req request, const char* info) { + LuaAfbContextT *afbContext = (LuaAfbContextT *)lua_newuserdata(luaState, sizeof(LuaAfbContextT)); + if (!afbContext) { + AFB_ERROR ("LuaCtxPush fail to allocate user data context"); + return NULL; + } + luaL_setmetatable(luaState, CTX_TOKEN); + afbContext->ctxMagic=CTX_MAGIC; + afbContext->info=strdup(info); + afbContext->request= request; + return afbContext; +} + +STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { + + free (afbContext->info); +} + // List Avaliable Configuration Files PUBLIC json_object* ScanForConfig (char* searchPath, char *pre, char *ext) { json_object *responseJ; @@ -80,17 +130,38 @@ PUBLIC json_object* ScanForConfig (char* searchPath, char *pre, char *ext) { return (responseJ); } -STATIC int LuaPrintNotice(lua_State* luaState) { - int count = lua_gettop(luaState); - - for (int idx=1; idx <= count; ++idx) { - const char *str = lua_tostring(luaState, idx); // Get string +STATIC int LuaPrintMessage(LuaAfbMessageT action, lua_State* luaState) { + + int count = lua_gettop(luaState); + for (int idx = 1; idx <= count; ++idx) { + const char *str = lua_tostring(luaState, idx); // Get string + + switch (action) { + case AFB_MSG_NOTICE: + AFB_NOTICE(str); + break; + + case AFB_MSG_WARNING: + AFB_WARNING(str); + break; + + default: + AFB_ERROR(str); + } + } + return 0; // no value return +} - // Output string. - AFB_NOTICE (str); - } +STATIC int LuaPrintWarning(lua_State* luaState) { + + LuaPrintMessage (AFB_MSG_WARNING, luaState); + return 0; // no value return +} - return 0; // no value return +STATIC int LuaPrintNotice(lua_State* luaState) { + + LuaPrintMessage (AFB_MSG_NOTICE, luaState); + return 0; // no value return } STATIC int LuaPushArgument (json_object *arg) { @@ -126,12 +197,185 @@ STATIC int LuaPushArgument (json_object *arg) { return 1; } +static json_object *LuaPopArgs (lua_State* luaState, int count); +STATIC json_object *PopOneArg (lua_State* luaState, int idx); +static json_object *LuaTableToJson (lua_State* luaState, int index) { + + json_object *tableJ= json_object_new_object(); + const char *key; + char number[3]; + lua_pushnil(luaState); // 1st key + for (int jdx=1; lua_next(luaState, index) != 0; jdx++) { + + printf("jdx=%d %s - %s\n", jdx, + lua_typename(luaState, lua_type(luaState, -2)), + lua_typename(luaState, lua_type(luaState, -1))); + + // uses 'key' (at index -2) and 'value' (at index -1) + if (lua_type(luaState,-2) == LUA_TSTRING) key= lua_tostring(luaState, -2); + else { + snprintf(number, sizeof(number),"%d", jdx); + key=number; + } + + json_object_object_add(tableJ, key, PopOneArg(luaState, -1)); + lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration + } + + return tableJ; +} + +STATIC json_object *PopOneArg (lua_State* luaState, int idx) { + json_object *value=NULL; + + switch(lua_type(luaState, idx)) { + case LUA_TNUMBER: + value= json_object_new_double(lua_tonumber(luaState, idx)); + break; + case LUA_TBOOLEAN: + value= json_object_new_boolean(lua_toboolean(luaState, idx)); + break; + case LUA_TSTRING: + value= json_object_new_string(lua_tostring(luaState, idx)); + break; + case LUA_TTABLE: { + AFB_NOTICE ("-++-- idx=%d ", idx); + value= LuaTableToJson(luaState, idx); + break; + } + default: + AFB_NOTICE ("script returned Unknown/Unsupported idx=%d type: %s", idx, lua_typename(luaState, idx)); + value=NULL; + } + if (value) AFB_NOTICE ("---- idx=%d value=%s", idx, json_object_get_string(value)); + + return value; +} + +static json_object *LuaPopArgs (lua_State* luaState, int count) { + + + json_object *responseJ; + + if(count <=0) return NULL; + + // start at 2 because we are using a function array lib + if (count == 2) { + responseJ=PopOneArg (luaState, 2); + } else { + // loop on remaining return arguments + responseJ= json_object_new_array(); + for (int idx=2; idx <= count; idx++) { + json_object_array_add(responseJ, PopOneArg (luaState, idx)); + } + } + + return responseJ; +} + + +STATIC int LuaAfbSuccess(lua_State* luaState) { + + + int count = lua_gettop(luaState); + + + //AFB_NOTICE ("LuaAfbSuccess args=%s",json_object_get_string(LuaPopArgs(luaState, count))); + + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, 1); + if (!afbContext) goto OnErrorExit; + + afb_req_success(afbContext->request, LuaPopArgs(luaState, count), NULL); + + LuaCtxFree(afbContext); + return 0; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbFail(lua_State* luaState) { + + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, 1); + if (!afbContext) goto OnErrorExit; + + int count = lua_gettop(luaState); + + afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(LuaPopArgs(luaState, count))); + + LuaCtxFree(afbContext); + return 0; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC void LuaAfbServiceCB(void *handle, int iserror, struct json_object *responseJ) { + LuaCallServiceT *contextCB= (LuaCallServiceT*)handle; + + // load function (should exist in CONTROL_PATH_LUA + lua_getglobal(luaState, contextCB->callback); + + // push error status & response + lua_pushboolean(luaState, iserror); + (void)LuaPushArgument(responseJ); + + int err=lua_pcall(luaState, 2, LUA_MULTRET, 0); + if (err) { + AFB_ERROR ("LUA-SERICE-CB:FAIL response=%s err=%s", json_object_get_string(responseJ), lua_tostring(luaState,-1) ); + } +} + +STATIC int LuaAfbService(lua_State* luaState) { + int count = lua_gettop(luaState); + + // retrieve userdate context + LuaAfbContextT *afbContext= luaL_checkudata(luaState, 1, "CTX_TOKEN"); + if (!afbContext) { + lua_pushliteral (luaState, "LuaAfbServiceCall-Hoops no CTX_TOKEN"); + goto OnErrorExit; + } + + if (count <5 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4) || !lua_isstring(luaState, 5)) { + lua_pushliteral (luaState, "LuaAfbServiceCall-Syntax is AFB_service_call (api, verb, query, callback, handle"); + goto OnErrorExit; + } + + LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); + + // get api/verb+query + const char *api = lua_tostring(luaState,1); + const char *verb= lua_tostring(luaState,2); + json_object *queryJ= LuaTableToJson(luaState, 3); + if (!queryJ) goto OnErrorExit; + + if (count >= 6) { + if (!lua_istable(luaState, 6)) { + lua_pushliteral (luaState, "LuaAfbServiceCall-Syntax optional handle should be a table"); + goto OnErrorExit; + } + contextCB->handle= lua_tostring(luaState, 5); + } + + afb_service_call(api, verb, queryJ, LuaAfbServiceCB, contextCB); + + return 0; // no value return + + OnErrorExit: + lua_error(luaState); + return 1; + +} + + // Generated some fake event based on watchdog/counter PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { int err, count=0; - json_object* queryJ = afb_req_json(request); + json_object* queryJ = afb_req_json(request); switch (action) { @@ -142,6 +386,10 @@ PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { AFB_ERROR ("LUA-DO-COMPILE:FAIL String=%s err=%s", script, lua_tostring(luaState,-1) ); goto OnErrorExit; } + // Push AFB client context on the stack + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, script); + if (!afbContext) goto OnErrorExit; + break; } @@ -154,9 +402,15 @@ PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { goto OnErrorExit; } + // Push AFB client context on the stack + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, func); + if (!afbContext) goto OnErrorExit; + // load function (should exist in CONTROL_PATH_LUA lua_getglobal(luaState, func); - + + + // push arguments on the stack if (json_object_get_type(args) != json_type_array) { count= LuaPushArgument (args); @@ -198,6 +452,9 @@ PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { } } + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, script); + if (!afbContext) goto OnErrorExit; + for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { char *filename; char*dirpath; json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); @@ -226,11 +483,7 @@ PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { AFB_ERROR ("LUA-DOSCRIPT HOOPs script=%s not in path=%s", script, CONTROL_PATH_LUA); goto OnErrorExit; - } - - //lua_setglobal(luaState, "args"); - count=1; - + } break; } @@ -238,59 +491,15 @@ PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { AFB_ERROR ("LUA-DOCALL-ACTION unknown query=%s", json_object_get_string(queryJ)); goto OnErrorExit; } - - // effectively exec LUA code -// err=lua_pcall(luaState, count, LUA_MULTRET, 0); - err=lua_pcall(luaState, count, LUA_MULTRET, 0); + + + // effectively exec LUA code (afb_reply/fail done later from callback) + err=lua_pcall(luaState, count, 0, 0); if (err) { AFB_ERROR ("LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1) ); goto OnErrorExit; } - // number of return values - count=lua_gettop(luaState); - - // Check status return true=OK false=fail - if (count == 0 || !lua_isboolean(luaState, 1)) { - AFB_ERROR ("LUA-DO-RETURN:INVALID 1st return argument not boolean query=%s", json_object_get_string(queryJ) ); - goto OnErrorExit; - } - - // get return fail/ok status - const int returnStatus=lua_toboolean(luaState, 1); - - // loop on remaining return arguments - json_object *returnArgs = json_object_new_array(); - for (int idx=2; idx <= count; idx++) { - - // push on stack return value (Fulup in LUA-5.3 the two functions are combined) - int valueType=lua_type (luaState, idx); - - switch(valueType) { - case LUA_TNUMBER: - json_object_array_add(returnArgs, json_object_new_double(lua_tonumber(luaState, idx))); - break; - case LUA_TBOOLEAN: - json_object_array_add(returnArgs, json_object_new_boolean(lua_toboolean(luaState, idx))); - break; - case LUA_TSTRING: - json_object_array_add(returnArgs, json_object_new_string(lua_tostring(luaState, idx))); - break; - case LUA_TTABLE: - default: - AFB_NOTICE ("script returned Unknown/Unsupported type: "); - } - - } - - // pop stack including Func/String/Script call - lua_pop(luaState, count+1); - - if(returnStatus) - afb_req_success(request, returnArgs, NULL); - else - afb_req_fail(request, "LUA-DOACTION-FAIL", json_object_get_string(returnArgs)); - return; OnErrorExit: @@ -298,21 +507,26 @@ PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) { return; } -PUBLIC void ctlapi_lua_dostring (afb_req request) { - +PUBLIC void ctlapi_lua_dostring (afb_req request) { LuaDoAction (LUA_DOSTRING, request); } PUBLIC void ctlapi_lua_docall (afb_req request) { - LuaDoAction (LUA_DOCALL, request); } PUBLIC void ctlapi_lua_doscript (afb_req request) { - LuaDoAction (LUA_DOSCRIPT, request); } +static const luaL_Reg afbFunction[] = { + {"notice" , LuaPrintNotice}, + {"warning", LuaPrintWarning}, + {"service", LuaAfbService}, + {"success", LuaAfbSuccess}, + {"fail" , LuaAfbFail}, + {NULL, NULL} /* sentinel */ +}; // Create Binding Event at Init PUBLIC int LuaLibInit () { @@ -332,8 +546,8 @@ PUBLIC int LuaLibInit () { luaL_openlibs(luaState); // redirect print to AFB_NOTICE - lua_register(luaState,"print", LuaPrintNotice ); - //lua_register(lauHandle,"AFB_DEBUG", LuaAFBDebug); + luaL_newlib(luaState, afbFunction); + lua_setglobal(luaState, "AFB"); // load+exec any file found in LUA search path for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { diff --git a/data/helloworld-lua-script.lua b/data/helloworld-lua-script.lua index 8386bc0..7dd0459 100644 --- a/data/helloworld-lua-script.lua +++ b/data/helloworld-lua-script.lua @@ -37,5 +37,5 @@ -- return two arguments on top of status - return true, 1234, "ABCD" + return true, 1234, "ABCD", 5678 diff --git a/data/onload-control-script.lua b/data/onload-control-script.lua index 7ded3be..ac316cd 100644 --- a/data/onload-control-script.lua +++ b/data/onload-control-script.lua @@ -23,14 +23,59 @@ count=0 -- Adjust Volume function of vehicle speed function Adjust_Volume_Speed (speed_meters_second) - message= string.format("**** Adjust_Volume_Speed speed=%d count=%d", speed_meters_second, count); - print (message); + AFB:notice("In Adjust_Volume_Speed") + + print (string.format("***** Adjust_Volume_Speed speed=%d count=%d", speed_meters_second, count)); -- compute volume volume = speed_meters_second * 2 count=count+1 - return true, volume, count + AFB:success (1234, volume, count, 5678) +end + + +function Test_Binder_CB (result, context) + + local myTable= { ["arg1"] = "myString", ["arg2"] = 1234, ["arg4"] = true, ["arg5"] = 3.1416 } + + AFB:notice ("In Test_Binder_CB", result, context) + + AFB:success (1234, "ABCD", myTable, 5678) + +end + +function Test_Binder_Call_Async () + + local query= { + ["arg1"] = "myString", + ["arg2"] = 1234, + ["arg4"] = true, + ["arg5"] = 3.1416, + } + + AFB:service("alsacore","ping", query, Test_Binder_CB, "myContext") + +end + +function Test_Binder_Call_Sync () + + local query= { + ["arg1"] = "myString", + ["arg2"] = 1234, + ["arg4"] = true, + ["arg5"] = 3.1416, + } + + err= AFB:service_sync ("alsacore","ping", query) + + if (err) then + AFB:fail ("AFB:service_call_sync fail"); + else + AFB:success (1234, "ABCD", myTable) + end + + end function Ping_Test(...) @@ -41,10 +86,9 @@ function Ping_Test(...) do print(" -- ", tostring(v)) end - - -- return two arguments on top of status - return true, 1234, "ABCD" + -- push response to client + AFB:success (true, 1234, "ABCD"); end diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 0207747..e46fe8e 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -313,6 +313,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 Audio-Common build/ALSA-afb @@ -334,6 +335,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 build/Alsa-Plugin/Alsa-Policy-Hook @@ -355,6 +357,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 Audio-Common build/Audio-Common @@ -424,6 +427,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 HAL-afb/HAL-interface Audio-Common build/HAL-afb/HAL-interface @@ -456,6 +460,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 HAL-afb/HAL-interface Audio-Common build/HAL-afb/HDA-intel @@ -477,6 +482,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 HAL-afb/HAL-interface Audio-Common build/HAL-afb/Jabra-Solemate @@ -498,6 +504,7 @@ ../../../opt/include/alsa /usr/include/p11-kit-1 /usr/include/json-c + /usr/include/lua5.3 HAL-afb/HAL-interface Audio-Common build/HAL-afb/Scarlett-Focusrite -- cgit 1.2.3-korg