From 61f0f263c335ad403c6693a1b8b6f5428ac180a8 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 16 Aug 2017 18:25:05 +0200 Subject: Fixed LUA Nested Table Issues. Added LUA2C for User Defined Plugins --- Alsa-Plugin/Alsa-Policy-Hook/README.md | 4 +- Audio-Common/filescan-utils.c | 2 +- Controler-afb/CMakeLists.txt | 9 +- Controler-afb/README.md | 31 +- Controler-afb/ctl-apidef.h | 34 +- Controler-afb/ctl-apidef.json | 2 +- Controler-afb/ctl-binding.c | 19 +- Controler-afb/ctl-binding.h | 52 +- Controler-afb/ctl-dispatch.c | 583 +++++++++++++--------- Controler-afb/ctl-lua.c | 50 +- Controler-afb/ctl-plugin-sample.c | 52 +- conf.d/cmake/config.cmake | 16 +- conf.d/project/config.d/onload-audio-control.json | 6 +- conf.d/project/lua.d/onload-audio-controls.lua | 25 +- nbproject/configurations.xml | 12 + 15 files changed, 557 insertions(+), 340 deletions(-) diff --git a/Alsa-Plugin/Alsa-Policy-Hook/README.md b/Alsa-Plugin/Alsa-Policy-Hook/README.md index e3f42fa..8fa2643 100644 --- a/Alsa-Plugin/Alsa-Policy-Hook/README.md +++ b/Alsa-Plugin/Alsa-Policy-Hook/README.md @@ -41,7 +41,9 @@ pcm.MyNavigationHook { # Request autorisation to write on navigation navigation-ctl { api "control" - verb "request" + verb "dispatch" + target "navigation" + args "{'any_valid': 'json object'}" } # subscribe to Audio Agent Event map them to signal subscribe-evt { diff --git a/Audio-Common/filescan-utils.c b/Audio-Common/filescan-utils.c index 9fa121b..8bb66d4 100644 --- a/Audio-Common/filescan-utils.c +++ b/Audio-Common/filescan-utils.c @@ -115,7 +115,7 @@ PUBLIC const char *GetBinderName() { // retrieve binder name from process name afb-name-trailer prctl(PR_GET_NAME, psName,NULL,NULL,NULL); - binderName=GetMidleName(psName); + binderName=(char*)GetMidleName(psName); return binderName; } \ No newline at end of file diff --git a/Controler-afb/CMakeLists.txt b/Controler-afb/CMakeLists.txt index 78e66c8..30fcb37 100644 --- a/Controler-afb/CMakeLists.txt +++ b/Controler-afb/CMakeLists.txt @@ -26,14 +26,19 @@ macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME) ) add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h) add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI) - endmacro(SET_TARGET_GENSKEL) +# Include LUA only when requested +if(CONTROL_SUPPORT_LUA) + message(STATUS "Notice: LUA Controler Support Selected") + set(CTL_LUA_SOURCE ctl-lua.c) +endif(CONTROL_SUPPORT_LUA) + # Add target to project dependency list PROJECT_TARGET_ADD(control-afb) # Define project Targets - ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-dispatch.c ctl-lua.c) + ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-dispatch.c ${CTL_LUA_SOURCE}) # Generate API-v2 hat from OpenAPI json definition SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) diff --git a/Controler-afb/README.md b/Controler-afb/README.md index 3274ede..3abe762 100644 --- a/Controler-afb/README.md +++ b/Controler-afb/README.md @@ -12,12 +12,12 @@ Controler AAAA(AGL Advance Audio Controler) and more. - Actions can either be: + Invocation to an other binding API, either internal or external (eg: a policy service, Alsa UCM, ...) + C routines from a user provider plugin (eg: policy routine, proprietary code, ...) - + LUA script function. LUA provides access to every AGL appfw functionalities and can be extended from C user provided plugins. + + Lua script function. Lua provides access to every AGL appfw functionalities and can be extended from C user provided plugins. ## Installation - Controler is a native part of AGL Advance Audio Framework but may be used independently with any other service or application binder. - Dependencies: the only dependencies are audio-common for JSON-WRAP and Filescan-utils capabilities. - - Controler relies on LUA-5.3, when not needed LUA might be removed at compilation time. + - Controler relies on Lua-5.3, when not needed Lua might be removed at compilation time. ## Config @@ -49,8 +49,9 @@ Defines startup time configuration. Onload may provide multiple initialisation p * info is optional * plugin provides optional unique plugin name. Plugin should follow "onload-bindername-xxxxx.ctlso" patern and are search into CONTROL_PLUGIN_PATH. When defined controller will execute user provided function context=CTLP_ONLOAD(label,version,info). - The context returned by this routine is provided back to any C routines call later by the controller. - * lua2c list of LUA commands shipped with provided plugin. + The context returned by this routine is provided back to any C routines call later by the controller. Note that Lua2C function + are prefix in Lua script with plugin label (eg: MyPlug: in following config sample) + * lua2c list of Lua commands shipped with provided plugin. * require list of binding that should be initialised before the controller starts. Note that some listed requirer binding might be absent, nevertheless any present binding from this list will be started before controller binding, missing ones generate a warning. * action the list of action to execute during loadtime. Any failure in action will prevent controller binding from starting. @@ -61,7 +62,7 @@ Defines a list of controls that are accessible through (api="control", verb="req * label mandatory * info optional - * privileges needed privileges to request this control + * permissions Cynara needed privileges to request this control (same as AppFw-V2) * action the list of actions ### Event section @@ -84,13 +85,16 @@ Controler support tree categories of actions. Each action return a status status in JSON configuration file. Controler client may also provided its own arguments from the query list. Targeted binding receives both arguments defined in the config file and the argument provided by controller client. * C-API, when defined in the onload section, the plugin may provided C native API with CTLP-CAPI(apiname, label, args, query, context). - Plugin may also create LUA command with CTLP-LUA2C(LuaFuncName, label, args, query, context). Where args+query are JSONC object + Plugin may also create Lua command with CTLP-Lua2C(LuaFuncName, label, args, query, context). Where args+query are JSONC object and context the value return from CTLP_ONLOAD function. Any missing value is set to NULL. - * LUA-API, when compiled with LUA option, the controller support action defined directly in LUA script. During "onload" phase the - controller search in CONTROL_LUA_PATH file with pattern "onload-bindername-xxxx.lua". Any file corresponding to this pattern - is automatically loaded. Any function defined in those LUA script can be called through a controller action. LUA functions receive + * Lua-API, when compiled with Lua option, the controller support action defined directly in Lua script. During "onload" phase the + controller search in CONTROL_Lua_PATH file with pattern "onload-bindername-xxxx.lua". Any file corresponding to this pattern + is automatically loaded. Any function defined in those Lua script can be called through a controller action. Lua functions receive three parameters (label, args, query). +Note: Lua added functions systematically prefix. AGL standard AppFw functions are prefixed with AGL: (eg: AGL:notice(), AGL_success(), ...). +User Lua functions added though the plugin and CTLP_Lua2C are prefix with plugin label (eg: MyPlug:HelloWorld1). + ## Config Sample Here after a simple configuration sample. @@ -106,7 +110,11 @@ Here after a simple configuration sample. "onload": [{ "label": "onload-default", "info": "onload initialisation config", - "plugin": "ctl-audio-plugin-sample.ctlso", + "plugin": { + "label" : "MyPlug", + "sharelib": "ctl-audio-plugin-sample.ctlso", + "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] + }, "require": ["intel-hda", "jabra-usb", "scarlett-usb"], "actions": [ { @@ -134,6 +142,7 @@ Here after a simple configuration sample. [ { "label": "multimedia", + "permissions": "urn:AGL:permission:audio:public:mutimedia", "actions": { "label": "multimedia-control-lua", "info": "Call Lua Script function Test_Lua_Engin", @@ -141,6 +150,7 @@ Here after a simple configuration sample. } }, { "label": "navigation", + "permissions": "urn:AGL:permission:audio:public:navigation", "actions": { "label": "navigation-control-lua", "info": "Call Lua Script to set Navigation", @@ -148,6 +158,7 @@ Here after a simple configuration sample. } }, { "label": "emergency", + "permissions": "urn:AGL:permission:audio:public:emergency", "actions": { "label": "emergency-control-ucm", "lua": "Audio_Set_Emergency" diff --git a/Controler-afb/ctl-apidef.h b/Controler-afb/ctl-apidef.h index 83b3308..9eb271d 100644 --- a/Controler-afb/ctl-apidef.h +++ b/Controler-afb/ctl-apidef.h @@ -37,20 +37,20 @@ static const char _afb_description_v2_control[] = "name\":\"delay\",\"required\":false,\"schema\":{\"type\":\"interger\"}}," "{\"in\":\"query\",\"name\":\"count\",\"required\":false,\"schema\":{\"ty" "pe\":\"interger\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/res" - "ponses/200\"}}}},\"/select\":{\"description\":\"Request Access to Naviga" - "tion Audio Channel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/component" - "s/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"name\"" - ":\"zone\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"respon" - "ses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_docal" - "l\":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-permiss" - "ions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"parameters" - "\":[{\"in\":\"query\",\"name\":\"func\",\"required\":true,\"schema\":{\"" - "type\":\"string\"}},{\"in\":\"query\",\"name\":\"args\",\"required\":fal" - "se,\"schema\":{\"type\":\"array\"}}],\"responses\":{\"200\":{\"$ref\":\"" - "#/components/responses/200\"}}}},\"/lua_dostring\":{\"description\":\"Ex" - "ecute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/comp" - "onents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"r" - "equired\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\"" + "ponses/200\"}}}},\"/dispatch\":{\"description\":\"Request Access to Navi" + "gation Audio Channel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/compone" + "nts/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"name" + "\":\"zone\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"resp" + "onses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_doc" + "all\":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-permi" + "ssions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"paramete" + "rs\":[{\"in\":\"query\",\"name\":\"func\",\"required\":true,\"schema\":{" + "\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"args\",\"required\":f" + "alse,\"schema\":{\"type\":\"array\"}}],\"responses\":{\"200\":{\"$ref\":" + "\"#/components/responses/200\"}}}},\"/lua_dostring\":{\"description\":\"" + "Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/co" + "mponents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"" + "required\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\"" ":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_doscript\":{\"descr" "iption\":\"Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$r" "ef\":\"#/components/x-permissions/navigation\"},\"parameters\":[{\"in\":" @@ -65,7 +65,7 @@ static const struct afb_auth _afb_auths_v2_control[] = { void ctlapi_monitor(struct afb_req req); void ctlapi_event_test(struct afb_req req); - void ctlapi_select(struct afb_req req); + void ctlapi_dispatch(struct afb_req req); void ctlapi_lua_docall(struct afb_req req); void ctlapi_lua_dostring(struct afb_req req); void ctlapi_lua_doscript(struct afb_req req); @@ -86,8 +86,8 @@ static const struct afb_verb_v2 _afb_verbs_v2_control[] = { .session = AFB_SESSION_NONE_V2 }, { - .verb = "select", - .callback = ctlapi_select, + .verb = "dispatch", + .callback = ctlapi_dispatch, .auth = &_afb_auths_v2_control[0], .info = NULL, .session = AFB_SESSION_NONE_V2 diff --git a/Controler-afb/ctl-apidef.json b/Controler-afb/ctl-apidef.json index 818dd80..93456ab 100644 --- a/Controler-afb/ctl-apidef.json +++ b/Controler-afb/ctl-apidef.json @@ -178,7 +178,7 @@ } } }, - "/select": { + "/dispatch": { "description": "Request Access to Navigation Audio Channel.", "get": { "x-permissions": { diff --git a/Controler-afb/ctl-binding.c b/Controler-afb/ctl-binding.c index 554199b..8771fc0 100644 --- a/Controler-afb/ctl-binding.c +++ b/Controler-afb/ctl-binding.c @@ -29,21 +29,6 @@ #include "ctl-apidef.h" -PUBLIC void ctlapi_navigation (afb_req request) { - - ctlapi_dispatch ("NAVIGATION", request); -} - -PUBLIC void ctlapi_multimedia (afb_req request) { - - ctlapi_dispatch ("MULTIMEDIA", request); -} - -PUBLIC void ctlapi_emergency (afb_req request) { - - ctlapi_dispatch ("EMERGENCY", request); -} - PUBLIC void ctlapi_monitor (afb_req request) { // subscribe Client to event @@ -66,11 +51,13 @@ PUBLIC int CtlBindingInit () { errcount += TimerEvtInit(); errcount += DispatchInit(); +#ifdef CONTROL_SUPPORT_LUA errcount += LuaLibInit(); +#endif // now that everything is initialised execute the onload action if (!errcount) - errcount += DispatchOneOnLoad(CONTROL_ONLOAD_DEFAULT); + errcount += DispatchOnLoad(CONTROL_ONLOAD_DEFAULT); AFB_DEBUG ("Audio Policy Control Binding Done errcount=%d", errcount); return errcount; diff --git a/Controler-afb/ctl-binding.h b/Controler-afb/ctl-binding.h index a2cedbf..33a9049 100644 --- a/Controler-afb/ctl-binding.h +++ b/Controler-afb/ctl-binding.h @@ -25,6 +25,12 @@ #include #include +#ifdef CONTROL_SUPPORT_LUA +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#endif + #ifndef PUBLIC #define PUBLIC #endif @@ -35,15 +41,6 @@ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #endif -// sharelib ctl-plugin* -typedef struct { - long magic; - char *label; -} CtlPluginMagicT; - -#define CTL_PLUGIN_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; - - // polctl-binding.c PUBLIC int CtlBindingInit (); @@ -71,15 +68,23 @@ typedef struct DispatchActionS{ const char* call; json_object *argsJ; int timeout; - int (*actionCB)(struct DispatchActionS *action, json_object *queryJ, void *context); + int (*actionCB)(const char*label, json_object *argsJ, json_object *queryJ, void *context); } DispatchActionT; +typedef int (*Lua2cFunctionT)(char *funcname, json_object *argsJ, void*context); PUBLIC int DispatchInit(void); -PUBLIC int DispatchOneOnLoad(const char *onLoadLabel); +PUBLIC int DispatchOnLoad(const char *onLoadLabel); PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ); -PUBLIC void ctlapi_dispatch (char* control, afb_req request); +PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback); +PUBLIC void ctlapi_dispatch (afb_req request); +#ifdef CONTROL_SUPPORT_LUA // ctl-lua.c +typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunctionT callback); + +#define CTLP_LUA2C(FuncName,label,argsJ, context) static int FuncName(char*label,json_object*argsJ, void*context);\ + int lua2c_ ## FuncName(lua_State* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(FuncName), FuncName));};\ + static int FuncName(char* label, json_object* argsJ, void* context) typedef enum { LUA_DOCALL, @@ -88,9 +93,30 @@ typedef enum { } LuaDoActionT; PUBLIC int LuaLibInit (); +PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count); +PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context); PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ); PUBLIC void ctlapi_lua_docall (afb_req request); PUBLIC void ctlapi_lua_dostring (afb_req request); PUBLIC void ctlapi_lua_doscript (afb_req request); -#endif +#else + typedef void* Lua2cWrapperT; +#endif // CONTROL_SUPPORT_LUA + + +// sharelib ctl-plugin* +typedef struct { + long magic; + char *label; +} CtlPluginMagicT; + + +#define MACRO_STR_VALUE(arg) #arg +#define CTLP_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; Lua2cWrapperT Lua2cWrap; +#define CTLP_ONLOAD(label,version,info) void* CtlPluginOnload(char* label, char* version, char* info) +#define CTLP_CAPI(funcname,label,argsJ, queryJ, context) int funcname(char* label, json_object* argsJ, json_object* queryJ, void* context) + + + +#endif // CONTROLER_BINDING_INCLUDE diff --git a/Controler-afb/ctl-dispatch.c b/Controler-afb/ctl-dispatch.c index 0594952..22bee27 100644 --- a/Controler-afb/ctl-dispatch.c +++ b/Controler-afb/ctl-dispatch.c @@ -27,7 +27,7 @@ typedef void*(*DispatchPluginInstallCbT)(const char* label, const char*version, const char*info); -static afb_req NULL_AFBREQ={}; +static afb_req NULL_AFBREQ = {}; typedef enum { CTL_DISPATCH_ONLOAD, @@ -42,12 +42,20 @@ typedef struct { } DispatchHandleT; typedef struct { - const char* label; + const char *label; const char *info; - const char *version; void *context; - char *plugin; + char *sharelib; void *dlHandle; + luaL_Reg *l2cFunc; + int l2cCount; +} DispatchPluginT; + +typedef struct { + const char* label; + const char *info; + const char *version; + DispatchPluginT *plugin; DispatchHandleT **onloads; DispatchHandleT **events; DispatchHandleT **controls; @@ -58,295 +66,348 @@ STATIC DispatchConfigT *configHandle = NULL; STATIC int DispatchControlToIndex(DispatchHandleT **controls, const char* controlLabel) { - for (int idx=0; controls[idx]; idx++) { + for (int idx = 0; controls[idx]; idx++) { if (!strcasecmp(controlLabel, controls[idx]->label)) return idx; } return -1; } -STATIC int DispatchOneControl (DispatchHandleT **controls, const char* controlLabel, json_object *queryJ, afb_req request) { +STATIC int DispatchOneControl(DispatchHandleT **controls, const char* controlLabel, json_object *queryJ, afb_req request) { int err; - if(!configHandle->controls) { - AFB_ERROR ("DISPATCH-CTL-API: No Control Action in Json config label=%s version=%s", configHandle->label, configHandle->version); + if (!configHandle) { + AFB_ERROR("DISPATCH-CTL-API: (Hoops/Bug!!!) No Config Loaded"); goto OnErrorExit; } - - int index=DispatchControlToIndex(controls, controlLabel); - if (index<0 || !controls[index]->actions) { - AFB_ERROR ("DISPATCH-CTL-API:NotFound label=%s in Json Control Config File", controlLabel); + + if (!configHandle->controls) { + AFB_ERROR("DISPATCH-CTL-API: No Control Action in Json config label=%s version=%s", configHandle->label, configHandle->version); goto OnErrorExit; - } + } + + int index = DispatchControlToIndex(controls, controlLabel); + if (index < 0 || !controls[index]->actions) { + AFB_ERROR("DISPATCH-CTL-API:NotFound/Error label=%s in Json Control Config File", controlLabel); + goto OnErrorExit; + } + + // Fulup (Bug/Feature) in current version is unique to every onload profile + if (configHandle->plugin && configHandle->plugin->l2cCount) { + LuaL2cNewLib (configHandle->plugin->label, configHandle->plugin->l2cFunc, configHandle->plugin->l2cCount); + } // loop on action for this control - DispatchActionT *actions=controls[index]->actions; - for (int idx=0; actions[idx].label; idx++) { - + DispatchActionT *actions = controls[index]->actions; + for (int idx = 0; actions[idx].label; idx++) { + switch (actions[idx].mode) { - case CTL_MODE_API: { + case CTL_MODE_API: + { json_object *returnJ; - - json_object_get( actions[idx].argsJ); // make sure afb_service_call does not free the argsJ + + json_object_get(actions[idx].argsJ); // make sure afb_service_call does not free the argsJ int err = afb_service_call_sync(actions[idx].api, actions[idx].call, actions[idx].argsJ, &returnJ); if (err) { - static const char*format="DispatchOneControl(Api) api=%s verb=%s args=%s"; + static const char*format = "DispatchOneControl(Api) api=%s verb=%s args=%s"; if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:API", format, actions[idx].label, actions[idx].api, actions[idx].call); - else AFB_ERROR (format, actions[idx].api, actions[idx].call, actions[idx].label); + else AFB_ERROR(format, actions[idx].api, actions[idx].call, actions[idx].label); goto OnErrorExit; } break; } - + +#ifdef CONTROL_SUPPORT_LUA case CTL_MODE_LUA: - err= LuaCallFunc (&actions[idx], queryJ); + err = LuaCallFunc(&actions[idx], queryJ); if (err) { - static const char*format= "DispatchOneControl(Lua) label=%s func=%s args=%s"; + static const char*format = "DispatchOneControl(Lua) label=%s func=%s args=%s"; if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Lua", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); - else AFB_ERROR (format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); goto OnErrorExit; } break; - +#endif + case CTL_MODE_CB: - err= (*actions[idx].actionCB) (&actions[idx], queryJ, configHandle->context); + err = (*actions[idx].actionCB) (actions[idx].label, actions[idx].argsJ, queryJ, configHandle->plugin->context); if (err) { - static const char*format="DispatchOneControl(Callback) label%s func=%s args=%s"; - if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Cb", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); - else AFB_ERROR (format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + static const char*format = "DispatchOneControl(Callback) label%s func=%s args=%s"; + if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Cb", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); goto OnErrorExit; } break; - - default:{ - static const char*format="DispatchOneControl(unknown) mode control=%s action=%s"; - AFB_ERROR (format, controls[index]->label); + + default: + { + static const char*format = "DispatchOneControl(unknown) mode control=%s action=%s"; + AFB_ERROR(format, controls[index]->label); if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:Unknown", format, controls[index]->label); - } + } } } - + // everything when fine - if(afb_req_is_valid(request))afb_req_success(request,NULL,controls[index]->label); + if (afb_req_is_valid(request))afb_req_success(request, NULL, controls[index]->label); return 0; - - OnErrorExit: + +OnErrorExit: return -1; } // Event name is mapped on control label and executed as a standard control -PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ){ - DispatchHandleT **events=configHandle->events; - (void)DispatchOneControl(events, evtLabel, eventJ, NULL_AFBREQ); +PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ) { + DispatchHandleT **events = configHandle->events; + + (void) DispatchOneControl(events, evtLabel, eventJ, NULL_AFBREQ); } // Event name is mapped on control label and executed as a standard control -PUBLIC int DispatchOneOnLoad(const char *onLoadLabel){ - DispatchHandleT **onloads=configHandle->onloads; - int err=DispatchOneControl(onloads, onLoadLabel, NULL, NULL_AFBREQ); +PUBLIC int DispatchOnLoad(const char *onLoadLabel) { + DispatchHandleT **onloads = configHandle->onloads; + + int err = DispatchOneControl(onloads, onLoadLabel, NULL, NULL_AFBREQ); return err; } -PUBLIC void ctlapi_dispatch (char* controlLabel, afb_req request) { - DispatchHandleT **controls=configHandle->controls; - - json_object* queryJ = afb_req_json(request); - (void)DispatchOneControl(controls, controlLabel, queryJ, request); -} +PUBLIC void ctlapi_dispatch(afb_req request) { + DispatchHandleT **controls = configHandle->controls; + json_object *queryJ, *argsJ; + const char *target; + + queryJ = afb_req_json(request); + int err = wrap_json_unpack(queryJ, "{s:s, s:o !}", "target", &target, "args", &argsJ); + if (err) { + afb_req_fail_f(request, "CTL-DISPTACH-INVALID", "missing target or args not a valid json object query=%s", json_object_get_string(queryJ)); + goto OnErrorExit; + } + + (void) DispatchOneControl(controls, target, argsJ, request); + +OnErrorExit: + return; +} + +// Wrapper to Lua2c plugin command add context dans delegate to LuaWrapper +PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback) { +#ifndef CONTROL_SUPPORT_LUA + AFB_ERROR("DISPATCH-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake"); + return 1; +#else + int err=Lua2cWrapper(luaState, funcname, callback, configHandle->plugin->context); + return err; +#endif +} + // List Avaliable Configuration Files -PUBLIC void ctlapi_config (struct afb_req request) { + +PUBLIC void ctlapi_config(struct afb_req request) { json_object*tmpJ; char *dirList; - + json_object* queryJ = afb_req_json(request); - if (queryJ && json_object_object_get_ex (queryJ, "cfgpath" , &tmpJ)) { - dirList = strdup (json_object_get_string(tmpJ)); - } else { - dirList = strdup (CONTROL_CONFIG_PATH); - AFB_NOTICE ("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH); + if (queryJ && json_object_object_get_ex(queryJ, "cfgpath", &tmpJ)) { + dirList = strdup(json_object_get_string(tmpJ)); + } else { + dirList = strdup(CONTROL_CONFIG_PATH); + AFB_NOTICE("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH); } - + // get list of config file struct json_object *responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, "onload", "json"); - + if (json_object_array_length(responseJ) == 0) { - afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH"); + afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH"); } else { afb_req_success(request, responseJ, NULL); } - + return; } // unpack individual action object -STATIC int DispatchLoadOneAction (DispatchConfigT *controlConfig, json_object *actionJ, DispatchActionT *action) { - char *api=NULL, *verb=NULL, *callback=NULL, *lua=NULL; - int err, modeCount=0; - err= wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s,s?o !}" - , "label",&action->label, "info",&action->info, "callback",&callback, "lua", &lua, "api",&api, "verb", &verb, "args",&action->argsJ); +STATIC int DispatchLoadOneAction(DispatchConfigT *controlConfig, json_object *actionJ, DispatchActionT *action) { + char *api = NULL, *verb = NULL, *callback = NULL, *lua = NULL; + int err, modeCount = 0; + + err = wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s,s?o !}" + , "label", &action->label, "info", &action->info, "callback", &callback, "lua", &lua, "api", &api, "verb", &verb, "args", &action->argsJ); if (err) { - AFB_ERROR ("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ)); + AFB_ERROR("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ)); goto OnErrorExit; } if (lua) { action->mode = CTL_MODE_LUA; - action->call=lua; + action->call = lua; modeCount++; } if (api && verb) { action->mode = CTL_MODE_API; - action->api=api; - action->call=verb; + action->api = api; + action->call = verb; modeCount++; } - if (callback && controlConfig->dlHandle) { + if (callback && controlConfig->plugin) { action->mode = CTL_MODE_CB; - action->call=callback; + action->call = callback; modeCount++; - action->actionCB = dlsym(controlConfig->dlHandle, callback); + action->actionCB = dlsym(controlConfig->plugin->dlHandle, callback); if (!action->actionCB) { - AFB_ERROR ("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, controlConfig->plugin); + AFB_ERROR("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, controlConfig->plugin->sharelib); goto OnErrorExit; } } // make sure at least one mode is selected if (modeCount == 0) { - AFB_ERROR ("DISPATCH-LOAD-ACTION No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); + AFB_ERROR("DISPATCH-LOAD-ACTION No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); goto OnErrorExit; - } + } if (modeCount > 1) { - AFB_ERROR ("DISPATCH-LOAD-ACTION:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); + AFB_ERROR("DISPATCH-LOAD-ACTION:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); goto OnErrorExit; - } - return 0; - + } + return 0; + OnErrorExit: - return -1; + return -1; }; -STATIC DispatchActionT *DispatchLoadActions (DispatchConfigT *controlConfig, json_object *actionsJ) { +STATIC DispatchActionT *DispatchLoadActions(DispatchConfigT *controlConfig, json_object *actionsJ) { int err; DispatchActionT *actions; - + // action array is close with a nullvalue; if (json_object_get_type(actionsJ) == json_type_array) { int count = json_object_array_length(actionsJ); - actions = calloc (count+1, sizeof(DispatchActionT)); - - for (int idx=0; idx < count; idx++) { + actions = calloc(count + 1, sizeof (DispatchActionT)); + + for (int idx = 0; idx < count; idx++) { json_object *actionJ = json_object_array_get_idx(actionsJ, idx); - err = DispatchLoadOneAction (controlConfig, actionJ, &actions[idx]); + err = DispatchLoadOneAction(controlConfig, actionJ, &actions[idx]); if (err) goto OnErrorExit; } - + } else { - actions = calloc (2, sizeof(DispatchActionT)); - err = DispatchLoadOneAction (controlConfig, actionsJ, &actions[0]); + actions = calloc(2, sizeof (DispatchActionT)); + err = DispatchLoadOneAction(controlConfig, actionsJ, &actions[0]); if (err) goto OnErrorExit; } - + return actions; - - OnErrorExit: + +OnErrorExit: return NULL; - + } -STATIC DispatchHandleT *DispatchLoadControl (DispatchConfigT *controlConfig, json_object *controlJ) { - json_object *actionsJ; +STATIC DispatchHandleT *DispatchLoadControl(DispatchConfigT *controlConfig, json_object *controlJ) { + json_object *actionsJ, *permissionsJ; int err; - - DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT)); - err= wrap_json_unpack(controlJ, "{ss,s?s,so !}", "label",&dispatchHandle->label, "info",&dispatchHandle->info, "actions",&actionsJ); + + DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT)); + err = wrap_json_unpack(controlJ, "{ss,s?s,s?o, so !}", "label", &dispatchHandle->label, "info", &dispatchHandle->info + , "permissions", &permissionsJ, "actions", &actionsJ); if (err) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ)); + AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ)); goto OnErrorExit; } - dispatchHandle->actions= DispatchLoadActions(controlConfig, actionsJ); + dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ); if (!dispatchHandle->actions) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label); - goto OnErrorExit; + AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label); + goto OnErrorExit; } return dispatchHandle; - - OnErrorExit: - return NULL; + +OnErrorExit: + return NULL; } -STATIC DispatchHandleT *DispatchLoadOnload (DispatchConfigT *controlConfig, json_object *onloadJ) { - json_object *actionsJ=NULL, *requireJ=NULL; +STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_object *onloadJ) { + json_object *actionsJ = NULL, *requireJ = NULL, *pluginJ = NULL; int err; - - DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT)); - err= wrap_json_unpack(onloadJ, "{ss,s?s,s?s,s?o,s?o !}", - "label",&dispatchHandle->label, "info",&dispatchHandle->info, "plugin", &controlConfig->plugin, "require", &requireJ, "actions",&actionsJ); + + DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT)); + err = wrap_json_unpack(onloadJ, "{ss,s?s,s?o,s?o,s?o !}", + "label", &dispatchHandle->label, "info", &dispatchHandle->info, "plugin", &pluginJ, "require", &requireJ, "actions", &actionsJ); if (err) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ)); + AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ)); goto OnErrorExit; } // best effort to initialise everything before starting if (requireJ) { - void DispatchRequireOneApi (json_object *bindindJ) { + void DispatchRequireOneApi(json_object * bindindJ) { const char* requireBinding = json_object_get_string(bindindJ); err = afb_daemon_require_api(requireBinding, 1); if (err) { - AFB_WARNING ("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding); + AFB_WARNING("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding); } } if (json_object_get_type(requireJ) == json_type_array) { - for (int idx=0; idx < json_object_array_length(requireJ); idx++) { - DispatchRequireOneApi (json_object_array_get_idx(requireJ, idx)); + for (int idx = 0; idx < json_object_array_length(requireJ); idx++) { + DispatchRequireOneApi(json_object_array_get_idx(requireJ, idx)); } } else { - DispatchRequireOneApi (requireJ); + DispatchRequireOneApi(requireJ); } } - if (controlConfig->plugin) { + if (pluginJ) { + json_object *lua2csJ = NULL; + DispatchPluginT *dPlugin= calloc(1, sizeof(DispatchPluginT)); + controlConfig->plugin = dPlugin; + + err = wrap_json_unpack(pluginJ, "{ss,s?s,ss,s?o!}", + "label", &dPlugin->label, "info", &dPlugin->info, "sharelib", &dPlugin->sharelib, "lua2c", &lua2csJ); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Plugin missing label|[info]|sharelib|[lua2c] in %s", json_object_get_string(onloadJ)); + goto OnErrorExit; + } // search for default policy config file - json_object *pluginPathJ = ScanForConfig(CONTROL_PLUGIN_PATH , CTL_SCAN_RECURSIVE, controlConfig->plugin, NULL); + json_object *pluginPathJ = ScanForConfig(CONTROL_PLUGIN_PATH, CTL_SCAN_RECURSIVE, dPlugin->sharelib, NULL); if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", controlConfig->plugin, CONTROL_PLUGIN_PATH); - goto OnErrorExit; + AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", dPlugin->sharelib, CONTROL_PLUGIN_PATH); + goto OnErrorExit; } - char *filename; char*fullpath; - err= wrap_json_unpack (json_object_array_get_idx(pluginPathJ,0), "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); + char *filename; + char*fullpath; + err = wrap_json_unpack(json_object_array_get_idx(pluginPathJ, 0), "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); if (err) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ)); + AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ)); goto OnErrorExit; } if (json_object_array_length(pluginPathJ) > 1) { - AFB_WARNING ("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", fullpath, filename); + AFB_WARNING("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", fullpath, filename); } char pluginpath[CONTROL_MAXPATH_LEN]; - strncpy(pluginpath, fullpath, sizeof(pluginpath)); - strncat(pluginpath, "/", sizeof(pluginpath)); - strncat(pluginpath, filename, sizeof(pluginpath)); - controlConfig->dlHandle = dlopen(pluginpath, RTLD_NOW); - if (!controlConfig->dlHandle) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror()); + strncpy(pluginpath, fullpath, sizeof (pluginpath)); + strncat(pluginpath, "/", sizeof (pluginpath)); + strncat(pluginpath, filename, sizeof (pluginpath)); + dPlugin->dlHandle = dlopen(pluginpath, RTLD_NOW); + if (!dPlugin->dlHandle) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror()); goto OnErrorExit; } - CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*)dlsym(controlConfig->dlHandle, "CtlPluginMagic"); + CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*) dlsym(dPlugin->dlHandle, "CtlPluginMagic"); if (!ctlPluginMagic || ctlPluginMagic->magic != CTL_PLUGIN_MAGIC) { AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath); goto OnErrorExit; @@ -355,173 +416,229 @@ STATIC DispatchHandleT *DispatchLoadOnload (DispatchConfigT *controlConfig, jso } // Jose hack to make verbosity visible from sharelib - struct afb_binding_data_v2 *afbHidenData = dlsym(controlConfig->dlHandle, "afbBindingV2data"); - if (afbHidenData) *afbHidenData = afbBindingV2data; + struct afb_binding_data_v2 *afbHidenData = dlsym(dPlugin->dlHandle, "afbBindingV2data"); + if (afbHidenData) *afbHidenData = afbBindingV2data; + + // Push lua2cWrapper @ into plugin + Lua2cWrapperT *lua2cInPlug = dlsym(dPlugin->dlHandle, "Lua2cWrap"); +#ifndef CONTROL_SUPPORT_LUA + if (lua2cInPlug) *lua2cInPlug = NULL; +#else + // Lua2cWrapper is part of binder and not expose to dynamic link + if (lua2cInPlug) *lua2cInPlug = DispatchOneL2c; + + { + int Lua2cAddOne(luaL_Reg *l2cFunc, const char* l2cName, int index) { + char funcName[CONTROL_MAXPATH_LEN]; + strncpy(funcName, "lua2c_", sizeof(funcName)); + strncat(funcName, l2cName, sizeof(funcName)); + + Lua2cFunctionT l2cFunction= (Lua2cFunctionT)dlsym(dPlugin->dlHandle, funcName); + if (!l2cFunction) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'%s' missing err=%s", funcName, dlerror()); + return 1; + } + l2cFunc[index].func=(void*)l2cFunction; + l2cFunc[index].name=strdup(l2cName); + + return 0; + } - DispatchPluginInstallCbT ctlPluginOnload = dlsym(controlConfig->dlHandle, "CtlPluginOnload"); + int errCount = 0; + luaL_Reg *l2cFunc=NULL; + int count=0; + + // look on l2c command and push them to LUA + if (json_object_get_type(lua2csJ) == json_type_array) { + int length = json_object_array_length(lua2csJ); + l2cFunc = calloc(length + 1, sizeof (luaL_Reg)); + for (count=0; count < length; count++) { + int err; + const char *l2cName = json_object_get_string(json_object_array_get_idx(lua2csJ, count)); + err = Lua2cAddOne(l2cFunc, l2cName, count); + if (err) errCount++; + } + } else { + l2cFunc = calloc(2, sizeof (luaL_Reg)); + const char *l2cName = json_object_get_string(lua2csJ); + errCount = Lua2cAddOne(l2cFunc, l2cName, 0); + count=1; + } + if (errCount) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin %d symbols not found in plugin='%s'", errCount, pluginpath); + goto OnErrorExit; + } else { + dPlugin->l2cFunc= l2cFunc; + dPlugin->l2cCount= count; + } + } +#endif + DispatchPluginInstallCbT ctlPluginOnload = dlsym(dPlugin->dlHandle, "CtlPluginOnload"); if (ctlPluginOnload) { - controlConfig->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info); + dPlugin->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info); } } - dispatchHandle->actions= DispatchLoadActions(controlConfig, actionsJ); + dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ); if (!dispatchHandle->actions) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchHandle->label); - goto OnErrorExit; + AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchHandle->label); + goto OnErrorExit; } return dispatchHandle; - - OnErrorExit: - return NULL; + +OnErrorExit: + return NULL; } -STATIC DispatchConfigT *DispatchLoadConfig (const char* filepath) { +STATIC DispatchConfigT *DispatchLoadConfig(const char* filepath) { json_object *controlConfigJ, *ignoreJ; int err; - + // Load JSON file - controlConfigJ= json_object_from_file(filepath); + controlConfigJ = json_object_from_file(filepath); if (!controlConfigJ) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath); + AFB_ERROR("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath); goto OnErrorExit; } - - AFB_INFO ("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath); - - json_object *metadataJ=NULL, *onloadsJ=NULL, *controlsJ=NULL, *eventsJ=NULL; - err= wrap_json_unpack(controlConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata",&metadataJ, "onload",&onloadsJ, "controls",&controlsJ, "events",&eventsJ); + + AFB_INFO("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath); + + json_object *metadataJ = NULL, *onloadsJ = NULL, *controlsJ = NULL, *eventsJ = NULL; + err = wrap_json_unpack(controlConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata", &metadataJ, "onload", &onloadsJ, "controls", &controlsJ, "events", &eventsJ); if (err) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(controlConfigJ)); + AFB_ERROR("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(controlConfigJ)); goto OnErrorExit; } - - DispatchConfigT *controlConfig = calloc (1, sizeof(DispatchConfigT)); + + DispatchConfigT *controlConfig = calloc(1, sizeof (DispatchConfigT)); if (metadataJ) { - err= wrap_json_unpack(metadataJ, "{ss,s?s,ss !}", "label", &controlConfig->label, "info",&controlConfig->info, "version",&controlConfig->version); + err = wrap_json_unpack(metadataJ, "{ss,s?s,ss !}", "label", &controlConfig->label, "info", &controlConfig->info, "version", &controlConfig->version); if (err) { - AFB_ERROR ("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ)); + AFB_ERROR("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ)); goto OnErrorExit; } - } - + } + if (onloadsJ) { DispatchHandleT *dispatchHandle; - + if (json_object_get_type(onloadsJ) != json_type_array) { - controlConfig->onloads = (DispatchHandleT**) calloc (2, sizeof(void*)); - dispatchHandle = DispatchLoadOnload (controlConfig, onloadsJ); - controlConfig->onloads[0]= dispatchHandle; - } else { - int length= json_object_array_length(onloadsJ); - controlConfig->onloads = (DispatchHandleT**) calloc (length+1, sizeof(void*)); - - for (int jdx=0; jdx< length; jdx++) { - json_object *onloadJ = json_object_array_get_idx(onloadsJ,jdx); - dispatchHandle = DispatchLoadOnload (controlConfig, onloadJ); - controlConfig->onloads[jdx]= dispatchHandle; + controlConfig->onloads = (DispatchHandleT**) calloc(2, sizeof (void*)); + dispatchHandle = DispatchLoadOnload(controlConfig, onloadsJ); + controlConfig->onloads[0] = dispatchHandle; + } else { + int length = json_object_array_length(onloadsJ); + controlConfig->onloads = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); + + for (int jdx = 0; jdx < length; jdx++) { + json_object *onloadJ = json_object_array_get_idx(onloadsJ, jdx); + dispatchHandle = DispatchLoadOnload(controlConfig, onloadJ); + controlConfig->onloads[jdx] = dispatchHandle; } - } + } } - + if (controlsJ) { DispatchHandleT *dispatchHandle; - + if (json_object_get_type(controlsJ) != json_type_array) { - controlConfig->controls = (DispatchHandleT**) calloc (2, sizeof(void*)); - dispatchHandle = DispatchLoadControl (controlConfig, controlsJ); - controlConfig->controls[0]= dispatchHandle; - } else { - int length= json_object_array_length(controlsJ); - controlConfig->controls = (DispatchHandleT**) calloc (length+1, sizeof(void*)); - - for (int jdx=0; jdx< length; jdx++) { - json_object *controlJ = json_object_array_get_idx(controlsJ,jdx); - dispatchHandle = DispatchLoadControl (controlConfig, controlJ); - controlConfig->controls[jdx]= dispatchHandle; + controlConfig->controls = (DispatchHandleT**) calloc(2, sizeof (void*)); + dispatchHandle = DispatchLoadControl(controlConfig, controlsJ); + controlConfig->controls[0] = dispatchHandle; + } else { + int length = json_object_array_length(controlsJ); + controlConfig->controls = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); + + for (int jdx = 0; jdx < length; jdx++) { + json_object *controlJ = json_object_array_get_idx(controlsJ, jdx); + dispatchHandle = DispatchLoadControl(controlConfig, controlJ); + controlConfig->controls[jdx] = dispatchHandle; } - } + } } - + if (eventsJ) { DispatchHandleT *dispatchHandle; - + if (json_object_get_type(eventsJ) != json_type_array) { - controlConfig->events = (DispatchHandleT**) calloc (2, sizeof(void*)); - dispatchHandle = DispatchLoadControl (controlConfig, eventsJ); - controlConfig->events[0]= dispatchHandle; - } else { - int length= json_object_array_length(eventsJ); - controlConfig->events = (DispatchHandleT**) calloc (length+1, sizeof(void*)); - - for (int jdx=0; jdx< length; jdx++) { - json_object *eventJ = json_object_array_get_idx(eventsJ,jdx); - dispatchHandle = DispatchLoadControl (controlConfig, eventJ); - controlConfig->events[jdx]= dispatchHandle; + controlConfig->events = (DispatchHandleT**) calloc(2, sizeof (void*)); + dispatchHandle = DispatchLoadControl(controlConfig, eventsJ); + controlConfig->events[0] = dispatchHandle; + } else { + int length = json_object_array_length(eventsJ); + controlConfig->events = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); + + for (int jdx = 0; jdx < length; jdx++) { + json_object *eventJ = json_object_array_get_idx(eventsJ, jdx); + dispatchHandle = DispatchLoadControl(controlConfig, eventJ); + controlConfig->events[jdx] = dispatchHandle; } } } - + return controlConfig; - + OnErrorExit: return NULL; } // Load default config file at init -PUBLIC int DispatchInit () { - int index, err, luaLoaded=0; + +PUBLIC int DispatchInit() { + int index, err, luaLoaded = 0; char controlFile [CONTROL_MAXPATH_LEN]; - - strncpy (controlFile,CONTROL_CONFIG_PRE, CONTROL_MAXPATH_LEN); - strncat (controlFile,"-", CONTROL_MAXPATH_LEN); - strncat (controlFile,GetBinderName(), CONTROL_MAXPATH_LEN); - + + strncpy(controlFile, CONTROL_CONFIG_PRE, CONTROL_MAXPATH_LEN); + strncat(controlFile, "-", CONTROL_MAXPATH_LEN); + strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); + // search for default dispatch config file - json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH, CTL_SCAN_RECURSIVE,controlFile, "json"); + json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH, CTL_SCAN_RECURSIVE, controlFile, "json"); // We load 1st file others are just warnings - for (index=0; index < json_object_array_length(responseJ); index++) { - json_object *entryJ=json_object_array_get_idx(responseJ, index); - - char *filename; char*fullpath; - err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); + for (index = 0; index < json_object_array_length(responseJ); index++) { + json_object *entryJ = json_object_array_get_idx(responseJ, index); + + char *filename; + char*fullpath; + err = wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); if (err) { - AFB_ERROR ("DISPATCH-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); + AFB_ERROR("DISPATCH-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); goto OnErrorExit; } if (index == 0) { if (strcasestr(filename, controlFile)) { char filepath[CONTROL_MAXPATH_LEN]; - strncpy(filepath, fullpath, sizeof(filepath)); - strncat(filepath, "/", sizeof(filepath)); - strncat(filepath, filename, sizeof(filepath)); - configHandle = DispatchLoadConfig (filepath); + strncpy(filepath, fullpath, sizeof (filepath)); + strncat(filepath, "/", sizeof (filepath)); + strncat(filepath, filename, sizeof (filepath)); + configHandle = DispatchLoadConfig(filepath); if (!configHandle) { - AFB_ERROR ("DISPATCH-INIT:ERROR Fail loading [%s]", filepath); + AFB_ERROR("DISPATCH-INIT:ERROR Fail loading [%s]", filepath); goto OnErrorExit; } - luaLoaded=1; + luaLoaded = 1; break; } } else { - AFB_WARNING ("DISPATCH-INIT:WARNING Secondary Control Config Ignored %s/%s", fullpath, filename); + AFB_WARNING("DISPATCH-INIT:WARNING Secondary Control Config Ignored %s/%s", fullpath, filename); } } - + // no dispatch config found remove control API from binder - if (!luaLoaded) { - AFB_WARNING ("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile); + if (!luaLoaded) { + AFB_WARNING("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile); } - - AFB_NOTICE ("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init"); + + AFB_NOTICE("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init"); return 0; - + OnErrorExit: - AFB_NOTICE ("DISPATCH-INIT:ERROR: Audio Control Dispatch Init"); - return 1; + AFB_NOTICE("DISPATCH-INIT:ERROR: Audio Control Dispatch Init"); + return 1; } - - + + diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c index bf02a31..affeb83 100644 --- a/Controler-afb/ctl-lua.c +++ b/Controler-afb/ctl-lua.c @@ -24,15 +24,12 @@ #include #include -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" #include "ctl-binding.h" #include "wrap-json.h" #define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg -#define LUA_MSG_MAX_LENGTH 255 +#define LUA_MSG_MAX_LENGTH 512 #define JSON_ERROR (json_object*)-1 static lua_State* luaState; @@ -160,20 +157,23 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx); STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { int idx; + #define LUA_KEY_INDEX -2 + #define LUA_VALUE_INDEX -1 json_object *tableJ= json_object_new_object(); const char *key; char number[3]; lua_pushnil(luaState); // 1st key + if (index < 0) index--; // nested table https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c for (idx=1; lua_next(luaState, index) != 0; idx++) { // uses 'key' (at index -2) and 'value' (at index -1) - if (lua_type(luaState,-2) == LUA_TSTRING) key= lua_tostring(luaState, -2); + if (lua_type(luaState,LUA_KEY_INDEX) == LUA_TSTRING) key= lua_tostring(luaState, LUA_KEY_INDEX); else { snprintf(number, sizeof(number),"%d", idx); key=number; } - json_object *argJ= PopOneArg(luaState, -1); + json_object *argJ= PopOneArg(luaState, LUA_VALUE_INDEX); json_object_object_add(tableJ, key, argJ); lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration } @@ -207,14 +207,9 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx) { case LUA_TSTRING: value= json_object_new_string(lua_tostring(luaState, idx)); break; - case LUA_TTABLE: { - if (idx > 0) { - value= LuaTableToJson(luaState, idx); - } else { - value= json_object_new_string("UNSUPPORTED_Lua_Nested_Table"); - } + case LUA_TTABLE: + value= LuaTableToJson(luaState, idx); break; - } case LUA_TNIL: value=json_object_new_string("nil") ; break; @@ -308,7 +303,13 @@ STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { } } else { - message[targetIdx++] = format[idx]; + if (targetIdx >= LUA_MSG_MAX_LENGTH) { + AFB_WARNING ("LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH); + targetIdx --; // move backward for EOL + break; + } else { + message[targetIdx++] = format[idx]; + } } } message[targetIdx]='\0'; @@ -357,7 +358,7 @@ STATIC int LuaPrintNotice(lua_State* luaState) { return err; } -STATIC int LuaPrintDebug(lua_State* luaState) { +STATIC int LuaPrintDebug(lua_State* luaState) { int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG); return err; } @@ -535,6 +536,16 @@ STATIC int LuaAfbPushEvent(lua_State* luaState) { return 1; } +// Function call from LUA when lua2c plugin L2C is used +PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context) { + + json_object *argsJ= LuaPopArgs(luaState, LUA_FIST_ARG); + int response = (*callback) (funcname, argsJ, context); + + // push response to LUA + lua_pushinteger(luaState, response); + return 1; +} // Generated some fake event based on watchdog/counter PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ) { @@ -733,6 +744,15 @@ PUBLIC void ctlapi_lua_doscript (afb_req request) { LuaDoAction (LUA_DOSCRIPT, request); } +// Register a new L2c list of LUA user plugin commands +PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count) { + // luaL_newlib(luaState, l2cFunc); macro does not work with pointer :( + luaL_checkversion(luaState); + lua_createtable(luaState, 0, count+1); + luaL_setfuncs(luaState,l2cFunc,0); + lua_setglobal(luaState, label); +} + static const luaL_Reg afbFunction[] = { {"notice" , LuaPrintNotice}, {"info" , LuaPrintInfo}, diff --git a/Controler-afb/ctl-plugin-sample.c b/Controler-afb/ctl-plugin-sample.c index 837ad9d..1d24487 100644 --- a/Controler-afb/ctl-plugin-sample.c +++ b/Controler-afb/ctl-plugin-sample.c @@ -31,9 +31,6 @@ typedef struct { int count; } MyPluginCtxT; -// Declare this sharelib as a Controller Plugin -CTL_PLUGIN_REGISTER("MyCtlSamplePlugin"); - STATIC const char* jsonToString (json_object *valueJ) { const char *value; if (valueJ) @@ -44,8 +41,11 @@ STATIC const char* jsonToString (json_object *valueJ) { return value; } +// Declare this sharelib as a Controller Plugin +CTLP_REGISTER("MyCtlSamplePlugin"); + // Call at initialisation time -PUBLIC void* CtlPluginOnload(char* label, char* version, char* info) { +PUBLIC CTLP_ONLOAD(label, version, info) { MyPluginCtxT *pluginCtx= (MyPluginCtxT*)calloc (1, sizeof(MyPluginCtxT)); pluginCtx->magic = MY_PLUGIN_MAGIC; pluginCtx->count = -1; @@ -54,7 +54,7 @@ PUBLIC void* CtlPluginOnload(char* label, char* version, char* info) { return (void*)pluginCtx; } -PUBLIC int SamplePolicyInit (DispatchActionT *action, json_object *argsJ, void *context) { +PUBLIC CTLP_CAPI (SamplePolicyInit, label, argsJ, queryJ, context) { MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:SamplePolicyInit (Hoops) Invalid Sample Plugin Context"); @@ -62,11 +62,11 @@ PUBLIC int SamplePolicyInit (DispatchActionT *action, json_object *argsJ, void * }; pluginCtx->count = 0; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Init label=%s args=%s\n", action->label, jsonToString(action->argsJ)); + AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Init label=%s args=%s\n", label, jsonToString(argsJ)); return 0; } -PUBLIC int sampleControlMultimedia (DispatchActionT *action, json_object *queryJ, void *context) { +PUBLIC CTLP_CAPI (sampleControlMultimedia,label, argsJ,queryJ,context) { MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { @@ -75,11 +75,11 @@ PUBLIC int sampleControlMultimedia (DispatchActionT *action, json_object *queryJ }; pluginCtx->count++; AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d" - , action->label, jsonToString(action->argsJ), jsonToString(queryJ), pluginCtx->count); + , label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); return 0; } -PUBLIC int sampleControlNavigation (DispatchActionT *action, json_object *queryJ, void *context) { +PUBLIC CTLP_CAPI (sampleControlNavigation, label, argsJ, queryJ, context) { MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { @@ -88,11 +88,11 @@ PUBLIC int sampleControlNavigation (DispatchActionT *action, json_object *queryJ }; pluginCtx->count++; AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlNavigation SamplePolicyCount action=%s args=%s query=%s count=%d" - ,action->label, jsonToString(action->argsJ), jsonToString(queryJ), pluginCtx->count); + ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); return 0; } -PUBLIC int SampleControlEvent (DispatchActionT *action, json_object *queryJ, void *context) { +PUBLIC CTLP_CAPI (SampleControlEvent, label, argsJ, queryJ, context) { MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { @@ -101,6 +101,34 @@ PUBLIC int SampleControlEvent (DispatchActionT *action, json_object *queryJ, voi }; pluginCtx->count++; AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d" - ,action->label, jsonToString(action->argsJ), jsonToString(queryJ), pluginCtx->count); + ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); + return 0; +} + +// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file +PUBLIC CTLP_LUA2C (Lua2cHelloWorld1, label, argsJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 SamplePolicyCount action=%s args=%s count=%d" + ,label, jsonToString(argsJ), pluginCtx->count); + return 0; +} + +// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file +PUBLIC CTLP_LUA2C (Lua2cHelloWorld2, label, argsJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 SamplePolicyCount action=%s args=%s count=%d" + ,label, jsonToString(argsJ), pluginCtx->count); return 0; } diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 73a00f6..4719486 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -65,9 +65,9 @@ set (PKG_REQUIRED_LIST lua>=5.3 ) + # Define CONTROL_CDEV_NAME should match MOST driver values # --------------------------------------------------------- - set(LUA_COMPILER "luac5.3" CACHE STRING "LUA syntaxe check") add_compile_options(-DCONTROL_ONLOAD_DEFAULT="onload-default") add_compile_options(-DCONTROL_MAXPATH_LEN=255) add_compile_options(-DCONTROL_DOSCRIPT_PRE="doscript") @@ -75,9 +75,17 @@ set (PKG_REQUIRED_LIST add_compile_options(-DCONTROL_CONFIG_POST="control" ) add_compile_options(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/config.d:${CMAKE_INSTALL_PREFIX}/controler/config.d") - add_compile_options(-DCONTROL_LUA_EVENT="luaevt") - add_compile_options(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controler/ctl-lua.d") - + + set(CONTROL_SUPPORT_LUA 1 CACHE BOOL "Active or not LUA Support") + if(CONTROL_SUPPORT_LUA) + set(LUA_COMPILER "luac5.3" CACHE STRING "LUA syntaxe check") + add_compile_options(-DCONTROL_SUPPORT_LUA) + add_compile_options(-DCONTROL_LUA_EVENT="luaevt") + add_compile_options(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controler/ctl-lua.d") + else(CONTROL_SUPPORT_LUA) + message(STATUS "Warning: LUA Without Support ") + endif(CONTROL_SUPPORT_LUA) + set (CTL_PLUGIN_PRE "ctl-" CACHE STRING "Prefix for Controler share plugin") set (CTL_PLUGIN_EXT ".ctlso" CACHE STRING "Postfix for Controler share plugin") add_compile_options(-DCTL_PLUGIN_MAGIC=2468013579) diff --git a/conf.d/project/config.d/onload-audio-control.json b/conf.d/project/config.d/onload-audio-control.json index 1a45f99..7180bd5 100644 --- a/conf.d/project/config.d/onload-audio-control.json +++ b/conf.d/project/config.d/onload-audio-control.json @@ -8,7 +8,11 @@ "onload": [{ "label": "onload-default", "info": "onload initialisation config", - "plugin": "ctl-audio-plugin-sample.ctlso", + "plugin": { + "label" : "MyPlug", + "sharelib": "ctl-audio-plugin-sample.ctlso", + "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] + }, "require": ["intel-hda", "jabra-usb", "scarlett-usb"], "actions": [ { diff --git a/conf.d/project/lua.d/onload-audio-controls.lua b/conf.d/project/lua.d/onload-audio-controls.lua index b6fd811..4849632 100644 --- a/conf.d/project/lua.d/onload-audio-controls.lua +++ b/conf.d/project/lua.d/onload-audio-controls.lua @@ -21,37 +21,34 @@ function Audio_Init_CB (status, result, context) print ("--inlua:Audio_Init_CB-- result=", Dump_Table(result)) print ("--inlua:Audio_Init_CB-- context=", Dump_Table(context)) - - - -- AFB:notice ("Audio_Init_Hal result='%s' context='%s'", result, context) - -- AFB:debug ("Audio_Init_Hal result=%s context=%s", {["ret1"]=5678, ["ret2"]="abcd"}, context) - + + AFB:notice("Audio_Init_Hal_CB result='%s' context='%s'", result, context) + end -- Function call at binding load time function Audio_Init_Hal(args, query) - local nextT = { + local nested = { ["next1"]=1234, ["next2"]="nested", ["next3"]=9999, } - - local response = { + local context = { ["arg1"]=1234, - ["arg2"]=nextT, + ["arg2"]=nested, ["arg3"]=5678, } - print ("--inlua:Audio_Init-- response=", Dump_Table(response)) - - AFB:notice ("**** in-lua table='%s' ****", response) + print ("--inlua:Audio_Init-- response=", Dump_Table(responseT)) + print("myplug=", Dump_Table(MyPlug)); - AFB:notice ("--LUA:Audio_Init_Hal args=%s query=%s", args, query); + -- This routine is defined in C sample plugin + local status=MyPlug:Lua2cHelloWorld1(nested) -- query asynchronously loaded HAL - AFB:service ('alsacore', 'hallist', {}, "Audio_Init_CB", {arg1=1234, arg2="toto"}) + AFB:service ('alsacore', 'hallist', {}, "Audio_Init_CB", context) end diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 8d7491c..fb247d1 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -207,6 +207,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -237,6 +238,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -267,6 +269,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -297,6 +300,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -337,6 +341,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -465,6 +470,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -496,6 +502,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -526,6 +533,7 @@ CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -602,6 +610,7 @@ CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_SUPPORT_LUA NATIVE_LINUX @@ -632,6 +641,7 @@ CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_SUPPORT_LUA NATIVE_LINUX hal_intel_hda_EXPORTS @@ -646,6 +656,7 @@ CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_SUPPORT_LUA NATIVE_LINUX hal_jabra_usb_EXPORTS @@ -660,6 +671,7 @@ CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_SUPPORT_LUA NATIVE_LINUX hal_scalett_usb_EXPORTS -- cgit 1.2.3-korg From a4899ab57f08aeb2741d08f74d7593c85a0ad3f4 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 16 Aug 2017 19:18:46 +0200 Subject: Fix DoScript Lua Updated Documentation. --- Audio-Common/filescan-utils.c | 4 ++-- Audio-Common/filescan-utils.h | 2 +- Controler-afb/README.md | 9 ++++++++ Controler-afb/ctl-dispatch.c | 3 +-- Controler-afb/ctl-lua.c | 33 ++++++++++++++-------------- conf.d/project/lua.d/doscript-helloworld.lua | 8 +++---- htdocs/audio-control.html | 2 +- 7 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Audio-Common/filescan-utils.c b/Audio-Common/filescan-utils.c index 8bb66d4..33dacdf 100644 --- a/Audio-Common/filescan-utils.c +++ b/Audio-Common/filescan-utils.c @@ -27,7 +27,7 @@ // List Avaliable Configuration Files -PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, char *pre, char *ext) { +PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, const char *pre, const char *ext) { json_object *responseJ; char *dirPath; char* dirList= strdup(searchPath); @@ -95,7 +95,7 @@ PUBLIC const char *GetMidleName(const char*name) { if (fullname[idx] == '-') { start = idx + 1; for (int jdx = start; fullname[jdx] != '\0'; jdx++) { - if (fullname[jdx] == '-') { + if (fullname[jdx] == '-' || fullname[jdx] == '.' || fullname[jdx] == '\0') { fullname[jdx] = '\0'; return &fullname[start]; break; diff --git a/Audio-Common/filescan-utils.h b/Audio-Common/filescan-utils.h index eba504e..671e728 100644 --- a/Audio-Common/filescan-utils.h +++ b/Audio-Common/filescan-utils.h @@ -35,7 +35,7 @@ typedef enum { PUBLIC const char *GetMidleName(const char*name); PUBLIC const char *GetBinderName(); -PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, char *pre, char *ext); +PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, const char *pre, const char *ext); #endif /* FILESCAN_UTILS_H */ diff --git a/Controler-afb/README.md b/Controler-afb/README.md index 3abe762..a81d4f7 100644 --- a/Controler-afb/README.md +++ b/Controler-afb/README.md @@ -95,6 +95,15 @@ Controler support tree categories of actions. Each action return a status status Note: Lua added functions systematically prefix. AGL standard AppFw functions are prefixed with AGL: (eg: AGL:notice(), AGL_success(), ...). User Lua functions added though the plugin and CTLP_Lua2C are prefix with plugin label (eg: MyPlug:HelloWorld1). +### Debugging Facilities + +Controler Lua script are check for syntax from CMAKE template with Luac. When needed to go further an developer API allow to +execute directly Lua command within controller context from Rest/Ws (api=control, verb=lua_doscript). DoScript API takes two +other optional arguments func=xxxx where xxxx is the function to execute within Lua script and args a JSON object to provide +input parameter. When funcname is not given by default the controller try to execute middle filename doscript-xxxx-????.lua. + +When executed from controller Lua script may use any AppFw Apis as well as any L2C user defined commands in plugin. + ## Config Sample Here after a simple configuration sample. diff --git a/Controler-afb/ctl-dispatch.c b/Controler-afb/ctl-dispatch.c index 22bee27..1afb846 100644 --- a/Controler-afb/ctl-dispatch.c +++ b/Controler-afb/ctl-dispatch.c @@ -589,8 +589,7 @@ PUBLIC int DispatchInit() { int index, err, luaLoaded = 0; char controlFile [CONTROL_MAXPATH_LEN]; - strncpy(controlFile, CONTROL_CONFIG_PRE, CONTROL_MAXPATH_LEN); - strncat(controlFile, "-", CONTROL_MAXPATH_LEN); + strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN); strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); // search for default dispatch config file diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c index affeb83..7c59186 100644 --- a/Controler-afb/ctl-lua.c +++ b/Controler-afb/ctl-lua.c @@ -595,7 +595,6 @@ PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ) { STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { int err, count=0; - const char *middleName=NULL; json_object* queryJ = afb_req_json(request); @@ -645,23 +644,23 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { case LUA_DOSCRIPT: { // Fulup need to fix argument passing const char *script; - char*func; + char*func=NULL; char *filename; char*fullpath; char luaScriptPath[CONTROL_MAXPATH_LEN]; - json_object *argsJ; + json_object *argsJ=NULL; int index; // scan luascript search path once static json_object *luaScriptPathJ =NULL; - if (!luaScriptPathJ) luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, CONTROL_DOSCRIPT_PRE, "lua"); - err= wrap_json_unpack (queryJ, "{s:s, s?s s?o s?o !}", "script", &script,"func", &func, "arg", &argsJ); + err= wrap_json_unpack (queryJ, "{s:s, s?s s?o !}", "script", &script,"func", &func, "args", &argsJ); if (err) { AFB_ERROR ("LUA-DOSCRIPT-SYNTAX:missing script|(args,arg) query=%s", json_object_get_string(queryJ)); goto OnErrorExit; } // search for filename=script in CONTROL_LUA_PATH + if (!luaScriptPathJ) luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE,CONTROL_DOSCRIPT_PRE "-", script); for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); @@ -671,17 +670,20 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { goto OnErrorExit; } - if (!middleName && !strcmp (filename, script)) { - middleName= GetMidleName(script); + if (index > 0) AFB_WARNING("LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); + else { strncpy (luaScriptPath, fullpath, sizeof(luaScriptPath)); strncat (luaScriptPath, "/", sizeof(luaScriptPath)); - strncat (luaScriptPath, filename, sizeof(luaScriptPath)); - - } else { - AFB_WARNING("LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); - } + strncat (luaScriptPath, filename, sizeof(luaScriptPath)); + } } + err= luaL_loadfile(luaState, luaScriptPath); + if (err) { + AFB_ERROR ("LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); + goto OnErrorExit; + } + // script was loaded we need to parse to make it executable err=lua_pcall(luaState, 0, 0, 0); if (err) { @@ -708,7 +710,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { lua_pushnil(luaState); count++; } else { - count+= LuaPushArgument (argsJ); + count+= LuaPushArgument(argsJ); } break; @@ -722,7 +724,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { // effectively exec LUA code (afb_reply/fail done later from callback) err=lua_pcall(luaState, count+1, 0, 0); if (err) { - AFB_ERROR ("LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1) ); + AFB_ERROR ("LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1)); goto OnErrorExit; } return; @@ -775,8 +777,7 @@ PUBLIC int LuaLibInit () { // search for default policy config file char fullprefix[CONTROL_MAXPATH_LEN]; - strncpy (fullprefix, CONTROL_CONFIG_PRE, sizeof(fullprefix)); - strncat (fullprefix, "-", sizeof(fullprefix)); + strncpy (fullprefix, CONTROL_CONFIG_PRE "-", sizeof(fullprefix)); strncat (fullprefix, GetBinderName(), sizeof(fullprefix)); strncat (fullprefix, "-", sizeof(fullprefix)); diff --git a/conf.d/project/lua.d/doscript-helloworld.lua b/conf.d/project/lua.d/doscript-helloworld.lua index b70ba8d..64bc94a 100644 --- a/conf.d/project/lua.d/doscript-helloworld.lua +++ b/conf.d/project/lua.d/doscript-helloworld.lua @@ -23,14 +23,14 @@ function helloworld (request, query) - AFB:notice ("LUA HelloWorld: simple test query=%s", query); + AFB:notice ("LUA HelloWorld: Simple test query=%s", query); if (query == nil) then - AFB:error ("LUA HelloWorld:FX query should not be empty"); + AFB:notice ("LUA HelloWorld:FX query should not be empty"); AFB:fail (request, "LUA HelloWorld: query should not be empty"); else - AFB:error ("LUA HelloWorld:OK query=%s", query); - AFB:sucess (request, {arg0="Demat", arg1="Bonjours", arg2="Gootentag", arg3="Morning"}); + AFB:notice ("LUA HelloWorld:OK query=%s", query); + AFB:success (request, {arg0="Demat", arg1="Bonjours", arg2="Gootentag", arg3="Morning"}); end end \ No newline at end of file diff --git a/htdocs/audio-control.html b/htdocs/audio-control.html index 89addcc..d51f527 100644 --- a/htdocs/audio-control.html +++ b/htdocs/audio-control.html @@ -31,7 +31,7 @@
  • -
  • +
  • -- cgit 1.2.3-korg From 5e919fde0a4c66b0203c46b8f06f303fcceaedde Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Thu, 17 Aug 2017 00:56:43 +0200 Subject: Implemented Timer and Event from Lua --- Controler-afb/CMakeLists.txt | 2 +- Controler-afb/ctl-apidef.h | 8 +- Controler-afb/ctl-apidef.json | 2 +- Controler-afb/ctl-binding.h | 15 ++ Controler-afb/ctl-events.c | 155 -------------- Controler-afb/ctl-lua.c | 293 +++++++++++++++++++++----- Controler-afb/ctl-timer.c | 156 ++++++++++++++ conf.d/project/lua.d/onload-audio-oncall.lua | 31 --- conf.d/project/lua.d/onload-audio-timer.lua | 73 +++++++ htdocs/audio-control.html | 1 + nbproject/configurations.xml | 302 ++++++++++----------------- 11 files changed, 602 insertions(+), 436 deletions(-) delete mode 100644 Controler-afb/ctl-events.c create mode 100644 Controler-afb/ctl-timer.c create mode 100644 conf.d/project/lua.d/onload-audio-timer.lua diff --git a/Controler-afb/CMakeLists.txt b/Controler-afb/CMakeLists.txt index 30fcb37..a9e8e60 100644 --- a/Controler-afb/CMakeLists.txt +++ b/Controler-afb/CMakeLists.txt @@ -38,7 +38,7 @@ endif(CONTROL_SUPPORT_LUA) PROJECT_TARGET_ADD(control-afb) # Define project Targets - ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-dispatch.c ${CTL_LUA_SOURCE}) + ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-timer.c ctl-dispatch.c ${CTL_LUA_SOURCE}) # Generate API-v2 hat from OpenAPI json definition SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) diff --git a/Controler-afb/ctl-apidef.h b/Controler-afb/ctl-apidef.h index 9eb271d..848fd14 100644 --- a/Controler-afb/ctl-apidef.h +++ b/Controler-afb/ctl-apidef.h @@ -31,7 +31,7 @@ static const char _afb_description_v2_control[] = " End\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions" "/monitor\"},\"parameters\":[{\"in\":\"query\",\"name\":\"event_patern\"," "\"required\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"20" - "0\":{\"$ref\":\"#/components/responses/200\"}}}},\"/event_test\":{\"desc" + "0\":{\"$ref\":\"#/components/responses/200\"}}}},\"/timer_test\":{\"desc" "ription\":\"Pause Resume Test\",\"get\":{\"x-permissions\":{\"$ref\":\"#" "/components/x-permissions/monitor\"},\"parameters\":[{\"in\":\"query\",\"" "name\":\"delay\",\"required\":false,\"schema\":{\"type\":\"interger\"}}," @@ -64,7 +64,7 @@ static const struct afb_auth _afb_auths_v2_control[] = { }; void ctlapi_monitor(struct afb_req req); - void ctlapi_event_test(struct afb_req req); + void ctlapi_timer_test(struct afb_req req); void ctlapi_dispatch(struct afb_req req); void ctlapi_lua_docall(struct afb_req req); void ctlapi_lua_dostring(struct afb_req req); @@ -79,8 +79,8 @@ static const struct afb_verb_v2 _afb_verbs_v2_control[] = { .session = AFB_SESSION_NONE_V2 }, { - .verb = "event_test", - .callback = ctlapi_event_test, + .verb = "timer_test", + .callback = ctlapi_timer_test, .auth = &_afb_auths_v2_control[0], .info = NULL, .session = AFB_SESSION_NONE_V2 diff --git a/Controler-afb/ctl-apidef.json b/Controler-afb/ctl-apidef.json index 93456ab..621fd5e 100644 --- a/Controler-afb/ctl-apidef.json +++ b/Controler-afb/ctl-apidef.json @@ -147,7 +147,7 @@ } } }, - "/event_test": { + "/timer_test": { "description": "Pause Resume Test", "get": { "x-permissions": { diff --git a/Controler-afb/ctl-binding.h b/Controler-afb/ctl-binding.h index 33a9049..c998007 100644 --- a/Controler-afb/ctl-binding.h +++ b/Controler-afb/ctl-binding.h @@ -24,6 +24,8 @@ #include #include #include +#include + #ifdef CONTROL_SUPPORT_LUA #include "lua.h" @@ -46,9 +48,22 @@ PUBLIC int CtlBindingInit (); // ctl-timerevt.c // ---------------------- +typedef int (*timerCallbackT)(void *context); + +typedef struct TimerHandleS { + int count; + int delay; + const char*label; + void *context; + timerCallbackT callback; + sd_event_source *evtSource; +} TimerHandleT; + PUBLIC int TimerEvtInit (void); PUBLIC afb_event TimerEvtGet(void); PUBLIC void ctlapi_event_test (afb_req request); +PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context); +PUBLIC void TimerEvtStop(TimerHandleT *timerHandle); // ctl-policy // ----------- diff --git a/Controler-afb/ctl-events.c b/Controler-afb/ctl-events.c deleted file mode 100644 index 18aac53..0000000 --- a/Controler-afb/ctl-events.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "ctl-binding.h" - -#define DEFAULT_PAUSE_DELAY 3000 -#define DEFAULT_TEST_COUNT 1 -typedef int (*timerCallbackT)(void *context); -typedef struct { - int value; - const char *label; -} AutoTestCtxT; - -typedef struct TimerHandleS { - int count; - int delay; - AutoTestCtxT *context; - timerCallbackT callback; - sd_event_source *evtSource; -} TimerHandleT; - -static afb_event afbevt; - -STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { - TimerHandleT *timerHandle = (TimerHandleT*) handle; - int done; - uint64_t usec; - - // Rearm timer if needed - timerHandle->count --; - if (timerHandle->count == 0) sd_event_source_unref(source); - else { - // otherwise validate timer for a new run - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); - sd_event_source_set_time(source, usec + timerHandle->delay); - } - - done= timerHandle->callback(timerHandle->context); - if (!done) goto OnErrorExit; - - return 0; - -OnErrorExit: - AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->context->label); - return -1; -} - - -STATIC int DoSendEvent (void *context) { - AutoTestCtxT *ctx= (AutoTestCtxT*)context; - json_object *ctlEventJ; - - if (ctx->value) ctx->value =0; - else ctx->value =1; - - ctlEventJ = json_object_new_object(); - json_object_object_add(ctlEventJ,"signal", json_object_new_string(ctx->label)); - json_object_object_add(ctlEventJ,"value" , json_object_new_int(ctx->value)); - int done = afb_event_push(afbevt, ctlEventJ); - - AFB_NOTICE ("DoSendEvent {action: '%s', value:%d} status=%d", ctx->label, ctx->value, done); - - return (done); -} - -STATIC void TimerEvtStart(TimerHandleT *timerHandle, void *context) { - uint64_t usec; - - // populate CB handle - timerHandle->callback=DoSendEvent; - timerHandle->context=context; - - // set a timer with ~250us accuracy - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay, 250, TimerNext, timerHandle); -} - -PUBLIC afb_event TimerEvtGet(void) { - return afbevt; -} - - -// Generated some fake event based on watchdog/counter -PUBLIC void ctlapi_event_test (afb_req request) { - json_object *queryJ, *tmpJ; - TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); - AutoTestCtxT *context = calloc (1, sizeof (AutoTestCtxT)); - int done; - - queryJ= afb_req_json(request); - - // Closing call only has one parameter - done=json_object_object_get_ex(queryJ, "closing", &tmpJ); - if (done) return; - - done=json_object_object_get_ex(queryJ, "label", &tmpJ); - if (!done) { - afb_req_fail_f(request, "TEST-LABEL-MISSING", "label is mandatory for event_test"); - goto OnErrorExit; - } - context->label = strdup(json_object_get_string (tmpJ)); - - json_object_object_get_ex(queryJ, "delay", &tmpJ); - timerHandle->delay = json_object_get_int (tmpJ) * 1000; - if (timerHandle->delay == 0) timerHandle->delay=DEFAULT_PAUSE_DELAY * 1000; - - json_object_object_get_ex(queryJ, "count", &tmpJ); - timerHandle->count = json_object_get_int (tmpJ); - if (timerHandle->count == 0) timerHandle->count=DEFAULT_TEST_COUNT; - - // start a lool timer - TimerEvtStart (timerHandle, context); - - afb_req_success(request, NULL, NULL); - return; - - OnErrorExit: - return; -} - -// Create Binding Event at Init -PUBLIC int TimerEvtInit () { - - // create binder event to send test pause/resume - afbevt = afb_daemon_make_event("control"); - if (!afb_event_is_valid(afbevt)) { - AFB_ERROR ("POLCTL_INIT: Cannot register ctl-events"); - return 1; - } - - AFB_DEBUG ("Audio Control-Events Init Done"); - return 0; -} - diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c index 7c59186..9d2cceb 100644 --- a/Controler-afb/ctl-lua.c +++ b/Controler-afb/ctl-lua.c @@ -31,6 +31,8 @@ #define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg #define LUA_MSG_MAX_LENGTH 512 #define JSON_ERROR (json_object*)-1 +static afb_req NULL_AFBREQ = {}; + static lua_State* luaState; @@ -47,12 +49,14 @@ static LuaAfbEvent *luaDefaultEvt; typedef struct { int ctxMagic; afb_req request; + void *handle; char *info; } LuaAfbContextT; typedef struct { const char *callback; json_object *context; + void *handle; } LuaCallServiceT; typedef enum { @@ -83,7 +87,7 @@ STATIC LuaAfbContextT *LuaCtxCheck (lua_State *luaState, int index) { return afbContext; } -STATIC LuaAfbContextT *LuaCtxPush (lua_State *luaState, afb_req request, const char* info) { +STATIC LuaAfbContextT *LuaCtxPush (lua_State *luaState, afb_req request, void *handle, const char* info) { // LuaAfbContextT *afbContext = (LuaAfbContextT *)lua_newuserdata(luaState, sizeof(LuaAfbContextT)); // luaL_setmetatable(luaState, CTX_TOKEN); LuaAfbContextT *afbContext = (LuaAfbContextT *)calloc(1, sizeof(LuaAfbContextT)); @@ -95,11 +99,13 @@ STATIC LuaAfbContextT *LuaCtxPush (lua_State *luaState, afb_req request, const c afbContext->ctxMagic=CTX_MAGIC; afbContext->info=strdup(info); afbContext->request= request; + afbContext->handle= handle; return afbContext; } STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { - free (afbContext->info); + free(afbContext->info); + free(afbContext); } // Push a json structure on the stack as a LUA table @@ -153,7 +159,7 @@ STATIC int LuaPushArgument (json_object *argsJ) { return 1; } -STATIC json_object *PopOneArg (lua_State* luaState, int idx); +STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx); STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { int idx; @@ -173,7 +179,7 @@ STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { snprintf(number, sizeof(number),"%d", idx); key=number; } - json_object *argJ= PopOneArg(luaState, LUA_VALUE_INDEX); + json_object *argJ= LuaPopOneArg(luaState, LUA_VALUE_INDEX); json_object_object_add(tableJ, key, argJ); lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration } @@ -186,7 +192,7 @@ STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { return tableJ; } -STATIC json_object *PopOneArg (lua_State* luaState, int idx) { +STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx) { json_object *value=NULL; int luaType = lua_type(luaState, idx); @@ -205,7 +211,7 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx) { value= json_object_new_boolean(lua_toboolean(luaState, idx)); break; case LUA_TSTRING: - value= json_object_new_string(lua_tostring(luaState, idx)); + value= json_object_new_string(lua_tostring(luaState, idx)); break; case LUA_TTABLE: value= LuaTableToJson(luaState, idx); @@ -213,9 +219,12 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx) { case LUA_TNIL: value=json_object_new_string("nil") ; break; + case LUA_TUSERDATA: + value=json_object_new_int64((int64_t)lua_touserdata(luaState, idx)); // store userdata as int !!! + break; default: - AFB_NOTICE ("PopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); + AFB_NOTICE ("LuaPopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); value=NULL; } @@ -230,12 +239,12 @@ static json_object *LuaPopArgs (lua_State* luaState, int start) { // start at 2 because we are using a function array lib if (start == stop) { - responseJ=PopOneArg (luaState, start); + responseJ=LuaPopOneArg (luaState, start); } else { // loop on remaining return arguments responseJ= json_object_new_array(); for (int idx=start; idx <= stop; idx++) { - json_object *argJ=PopOneArg (luaState, idx); + json_object *argJ=LuaPopOneArg (luaState, idx); if (!argJ) goto OnErrorExit; json_object_array_add(responseJ, argJ); } @@ -413,6 +422,8 @@ STATIC void LuaAfbServiceCB(void *handle, int iserror, struct json_object *respo if (err) { AFB_ERROR ("LUA-SERICE-CB:FAIL response=%s err=%s", json_object_get_string(responseJ), lua_tostring(luaState,-1) ); } + + free (contextCB); } @@ -472,60 +483,69 @@ STATIC int LuaAfbServiceSync(lua_State* luaState) { return 1; } -STATIC int LuaAfbMakeEvent(lua_State* luaState) { - int count = lua_gettop(luaState); - LuaAfbEvent *afbevt=calloc(1,sizeof(LuaAfbEvent)); +STATIC int LuaAfbEventPush(lua_State* luaState) { + LuaAfbEvent *afbevt; + int index; - if (count != 1 || !lua_isstring(luaState, 1)) { - lua_pushliteral (luaState, "LuaAfbMakeEvent-Syntax is evtHandle= AFB:event ('myEventName')"); - goto OnErrorExit; + // if no private event handle then use default binding event + if (lua_islightuserdata(luaState, LUA_FIST_ARG)) { + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG); + index=LUA_FIST_ARG+1; + } else { + index=LUA_FIST_ARG; + afbevt=luaDefaultEvt; } - - // event name should be the only argument - afbevt->name= strdup (lua_tostring(luaState,1)); - // create a new binder event - afbevt->event = afb_daemon_make_event(afbevt->name); if (!afb_event_is_valid(afbevt->event)) { - lua_pushliteral (luaState, "LuaAfbMakeEvent-Fail to Create Binder event"); + lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event"); goto OnErrorExit; } - - // push event handler as a LUA opaque handle - lua_pushlightuserdata(luaState, afbevt); - return 1; + + json_object *ctlEventJ= LuaTableToJson(luaState, index); + if (!ctlEventJ) { + lua_pushliteral (luaState, "LuaAfbEventPush-Syntax is AFB:signal ([evtHandle], {lua table})"); + goto OnErrorExit; + } + + int done = afb_event_push(afbevt->event, ctlEventJ); + if (!done) { + lua_pushliteral (luaState, "LuaAfbEventPush-Fail No Subscriber to event"); + AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); + goto OnErrorExit; + } + afbevt->count++; + return 0; OnErrorExit: lua_error(luaState); return 1; } -STATIC int LuaAfbPushEvent(lua_State* luaState) { +STATIC int LuaAfbEventSubscribe(lua_State* luaState) { LuaAfbEvent *afbevt; - int index; - + + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) { + lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail Invalid request handle"); + goto OnErrorExit; + } + // if no private event handle then use default binding event - if (lua_islightuserdata(luaState, 1)) { - afbevt = (LuaAfbEvent*) lua_touserdata(luaState, 1); - index=1; + if (lua_islightuserdata(luaState, LUA_FIST_ARG+1)) { + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG+1); } else { - index=2; afbevt=luaDefaultEvt; } - if (!lua_isstring(luaState, index)) { - lua_pushliteral (luaState, "LuaAfbPushEvent-Syntax is AFB:signal ([evtHandle], 'myEventName', 'data-1', ... 'data-n')"); - goto OnErrorExit; + if (!afb_event_is_valid(afbevt->event)) { + lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event handle"); + goto OnErrorExit; } - - // use every other arguments as event parameters - index++; - json_object *ctlEventJ= LuaTableToJson(luaState, index); - - int done = afb_event_push(afbevt->event, ctlEventJ); - if (!done) { - lua_pushliteral (luaState, "LuaAfbPushEvent-Fail to Push Binder event"); - AFB_ERROR ("LuaAfbPushEvent-Fail to Push Binder event=%s count=%d", afbevt->name, afbevt->count); + + int err = afb_req_subscribe(afbContext->request, afbevt->event); + if (err) { + lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail No Subscriber to event"); + AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); goto OnErrorExit; } afbevt->count++; @@ -536,6 +556,34 @@ STATIC int LuaAfbPushEvent(lua_State* luaState) { return 1; } +STATIC int LuaAfbEventMake(lua_State* luaState) { + int count = lua_gettop(luaState); + LuaAfbEvent *afbevt=calloc(1,sizeof(LuaAfbEvent)); + + if (count != LUA_FIST_ARG || !lua_isstring(luaState, LUA_FIST_ARG)) { + lua_pushliteral (luaState, "LuaAfbEventMake-Syntax is evtHandle= AFB:event ('myEventName')"); + goto OnErrorExit; + } + + // event name should be the only argument + afbevt->name= strdup (lua_tostring(luaState,LUA_FIST_ARG)); + + // create a new binder event + afbevt->event = afb_daemon_make_event(afbevt->name); + if (!afb_event_is_valid(afbevt->event)) { + lua_pushliteral (luaState, "LuaAfbEventMake-Fail to Create Binder event"); + goto OnErrorExit; + } + + // push event handler as a LUA opaque handle + lua_pushlightuserdata(luaState, afbevt); + return 1; + + OnErrorExit: + lua_error(luaState); + return 1; +} + // Function call from LUA when lua2c plugin L2C is used PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context) { @@ -608,7 +656,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { goto OnErrorExit; } // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, script); + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request,NULL,script); if (!afbContext) goto OnErrorExit; break; @@ -628,7 +676,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { lua_getglobal(luaState, func); // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, func); + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); if (!afbContext) goto OnErrorExit; // push query on the stack @@ -702,7 +750,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { lua_getglobal(luaState, func); // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, func); + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); if (!afbContext) goto OnErrorExit; // push function arguments @@ -746,6 +794,131 @@ PUBLIC void ctlapi_lua_doscript (afb_req request) { LuaDoAction (LUA_DOSCRIPT, request); } +STATIC int LuaTimerClear (lua_State* luaState) { + + // Get Timer Handle + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) goto OnErrorExit; + + // retrieve useful information opaque handle + TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; + + AFB_NOTICE ("LuaTimerClear timer=%s", timerHandle->label); + TimerEvtStop(timerHandle); + + return 0; //happy end + +OnErrorExit: + return 1; +} +STATIC int LuaTimerGet (lua_State* luaState) { + + // Get Timer Handle + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) goto OnErrorExit; + + // retrieve useful information opaque handle + TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; + + // create response as a JSON object + json_object *responseJ= json_object_new_object(); + json_object_object_add(responseJ,"label", json_object_new_string(timerHandle->label)); + json_object_object_add(responseJ,"delay", json_object_new_int(timerHandle->delay)); + json_object_object_add(responseJ,"count", json_object_new_int(timerHandle->count)); + + // return JSON object as Lua table + int count=LuaPushArgument(responseJ); + + // free json object + json_object_put(responseJ); + + return count; // return argument + +OnErrorExit: + return 0; +} + +// Timer Callback + +// Set timer +STATIC int LuaTimerSetCB (void *handle) { + LuaCallServiceT *contextCB =(LuaCallServiceT*) handle; + TimerHandleT *timerHandle = (TimerHandleT*) contextCB->handle; + int count; + + // push timer handle and user context on Lua stack + lua_getglobal(luaState, contextCB->callback); + + // Push timer handle + LuaAfbContextT *afbContext= LuaCtxPush(luaState, NULL_AFBREQ, contextCB->handle, timerHandle->label); + if (!afbContext) goto OnErrorExit; + count=1; + + // Push user Context + count+= LuaPushArgument(contextCB->context); + + int err=lua_pcall(luaState, count, LUA_MULTRET, 0); + if (err) { + AFB_ERROR ("LUA-TIMER-CB:FAIL response=%s err=%s", json_object_get_string(contextCB->context), lua_tostring(luaState,-1)); + goto OnErrorExit; + } + + // get return parameter + if (!lua_isboolean(luaState, -1)) { + return (lua_toboolean(luaState, -1)); + } + + // timer last run free context resource + if (timerHandle->count == 1) { + LuaCtxFree(afbContext); + } + return 0; // By default we are happy + + OnErrorExit: + return 1; // stop timer +} + +STATIC int LuaTimerSet(lua_State* luaState) { + const char *label=NULL, *info=NULL; + int delay=0, count=0; + + json_object *timerJ = LuaPopOneArg(luaState, LUA_FIST_ARG); + const char *callback = lua_tostring(luaState, LUA_FIST_ARG + 1); + json_object *contextJ = LuaPopOneArg(luaState, LUA_FIST_ARG + 2); + + if (lua_gettop(luaState) != LUA_FIST_ARG+2 || !timerJ || !callback || !contextJ) { + lua_pushliteral(luaState, "LuaTimerSet-Syntax timerset (timerT, 'callback', contextT)"); + goto OnErrorExit; + } + + int err = wrap_json_unpack(timerJ, "{ss, s?s si, si !}", "label", &label, "info", &info, "delay", &delay, "count", &count); + if (err) { + lua_pushliteral(luaState, "LuaTimerSet-Syntax timerT={label:xxx delay:ms, count:xx}"); + goto OnErrorExit; + } + + // everything look fine create timer structure + TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); + timerHandle->delay=delay; + timerHandle->count=count; + timerHandle->label=label; + + // Allocate handle to store context and callback + LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); + contextCB->callback= callback; + contextCB->context = contextJ; + contextCB->handle = timerHandle; + + // fire timer + TimerEvtStart (timerHandle, LuaTimerSetCB, contextCB); + + return 0; // Happy No Return Function + +OnErrorExit: + lua_error(luaState); + return 1; // return error code +} + // Register a new L2c list of LUA user plugin commands PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count) { // luaL_newlib(luaState, l2cFunc); macro does not work with pointer :( @@ -756,17 +929,21 @@ PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count) { } static const luaL_Reg afbFunction[] = { - {"notice" , LuaPrintNotice}, - {"info" , LuaPrintInfo}, - {"warning", LuaPrintWarning}, - {"debug" , LuaPrintDebug}, - {"error" , LuaPrintError}, - {"callsync", LuaAfbServiceSync}, - {"service", LuaAfbService}, - {"success", LuaAfbSuccess}, - {"fail" , LuaAfbFail}, - {"event" , LuaAfbMakeEvent}, - {"signal" , LuaAfbPushEvent}, + {"timerclear", LuaTimerClear}, + {"timerget" , LuaTimerGet}, + {"timerset" , LuaTimerSet}, + {"notice" , LuaPrintNotice}, + {"info" , LuaPrintInfo}, + {"warning" , LuaPrintWarning}, + {"debug" , LuaPrintDebug}, + {"error" , LuaPrintError}, + {"callsync" , LuaAfbServiceSync}, + {"service" , LuaAfbService}, + {"success" , LuaAfbSuccess}, + {"fail" , LuaAfbFail}, + {"subscribe" , LuaAfbEventSubscribe}, + {"evtmake" , LuaAfbEventMake}, + {"evtpush" , LuaAfbEventPush}, {NULL, NULL} /* sentinel */ }; diff --git a/Controler-afb/ctl-timer.c b/Controler-afb/ctl-timer.c new file mode 100644 index 0000000..f7ee6f0 --- /dev/null +++ b/Controler-afb/ctl-timer.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "ctl-binding.h" + +#define DEFAULT_PAUSE_DELAY 3000 +#define DEFAULT_TEST_COUNT 1 +typedef struct { + int value; + const char *label; +} AutoTestCtxT; + +static afb_event afbevt; + +STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { + TimerHandleT *timerHandle = (TimerHandleT*) handle; + int done; + uint64_t usec; + + // Rearm timer if needed + timerHandle->count --; + if (timerHandle->count == 0) { + sd_event_source_unref(source); + free (handle); + return 0; + } + else { + // otherwise validate timer for a new run + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); + sd_event_source_set_time(source, usec + timerHandle->delay*1000); + } + + done= timerHandle->callback(timerHandle->context); + if (!done) goto OnErrorExit; + + return 0; + +OnErrorExit: + AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->label); + return -1; +} + +PUBLIC void TimerEvtStop(TimerHandleT *timerHandle) { + + sd_event_source_unref(timerHandle->evtSource); + free (timerHandle); +} + + +PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context) { + uint64_t usec; + + // populate CB handle + timerHandle->callback=callback; + timerHandle->context=context; + + // set a timer with ~250us accuracy + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay*1000, 250, TimerNext, timerHandle); +} + +PUBLIC afb_event TimerEvtGet(void) { + return afbevt; +} + + +STATIC int DoSendEvent (void *context) { + AutoTestCtxT *ctx= (AutoTestCtxT*)context; + json_object *ctlEventJ; + + if (ctx->value) ctx->value =0; + else ctx->value =1; + + ctlEventJ = json_object_new_object(); + json_object_object_add(ctlEventJ,"signal", json_object_new_string(ctx->label)); + json_object_object_add(ctlEventJ,"value" , json_object_new_int(ctx->value)); + int done = afb_event_push(afbevt, ctlEventJ); + + AFB_NOTICE ("DoSendEvent {action: '%s', value:%d} status=%d", ctx->label, ctx->value, done); + + return (done); +} + +// Generated some fake event based on watchdog/counter +PUBLIC void ctlapi_timer_test (afb_req request) { + json_object *queryJ, *tmpJ; + TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); + AutoTestCtxT *context = calloc (1, sizeof (AutoTestCtxT)); + int done; + + queryJ= afb_req_json(request); + + // Closing call only has one parameter + done=json_object_object_get_ex(queryJ, "closing", &tmpJ); + if (done) return; + + done=json_object_object_get_ex(queryJ, "label", &tmpJ); + if (!done) { + afb_req_fail_f(request, "TEST-LABEL-MISSING", "label is mandatory for event_test"); + goto OnErrorExit; + } + timerHandle->label = strdup(json_object_get_string (tmpJ)); + + json_object_object_get_ex(queryJ, "delay", &tmpJ); + timerHandle->delay = json_object_get_int (tmpJ) * 1000; + if (timerHandle->delay == 0) timerHandle->delay=DEFAULT_PAUSE_DELAY * 1000; + + json_object_object_get_ex(queryJ, "count", &tmpJ); + timerHandle->count = json_object_get_int (tmpJ); + if (timerHandle->count == 0) timerHandle->count=DEFAULT_TEST_COUNT; + + // start a lool timer + TimerEvtStart (timerHandle, DoSendEvent, context); + + afb_req_success(request, NULL, NULL); + return; + + OnErrorExit: + return; +} + +// Create Binding Event at Init +PUBLIC int TimerEvtInit () { + + // create binder event to send test pause/resume + afbevt = afb_daemon_make_event("control"); + if (!afb_event_is_valid(afbevt)) { + AFB_ERROR ("POLCTL_INIT: Cannot register ctl-events"); + return 1; + } + + AFB_DEBUG ("Audio Control-Events Init Done"); + return 0; +} + diff --git a/conf.d/project/lua.d/onload-audio-oncall.lua b/conf.d/project/lua.d/onload-audio-oncall.lua index 13cda4b..08b25e5 100644 --- a/conf.d/project/lua.d/onload-audio-oncall.lua +++ b/conf.d/project/lua.d/onload-audio-oncall.lua @@ -68,34 +68,3 @@ function Test_Call_Sync (request, args) end end --- create a new event name -function Test_Event_Make (request, args) - - AFB:notice ("Test_Event_Make args=%s", args) - - local err evt_handle= AFB:event (args["evtname"]) - if (err) then - AFB:fail ("AFB:Test_Event_Make fail event=%s", args["evtname"]); - else - AFB:success (request, {}) - end - - local evtData = { - ["val1"]="My 1st private Event", - ["val2"]=5678 - } - - AFB:notify (evt_handle, evtData) -end - --- send an event on default binder event -function Test_Event_Notify (request, args) - - AFB:notice ("Test_Event_Notify args=%s", args) - local err AFB:notify (args) - if (err) then - AFB:fail ("AFB:Test_Event_Make fail event=%s", args["evtname"]); - else - AFB:success (request, {}) - end -end diff --git a/conf.d/project/lua.d/onload-audio-timer.lua b/conf.d/project/lua.d/onload-audio-timer.lua new file mode 100644 index 0000000..5f25de7 --- /dev/null +++ b/conf.d/project/lua.d/onload-audio-timer.lua @@ -0,0 +1,73 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Provide Sample Timer Handing to push event from LUA +--]] + +-- Create event on Lua script load +print ("*** Create MyTestEvent ***") +MyEventHandle= AFB:evtmake("MyTestEvent") + +-- Call count time every delay/ms +function Timer_Test_CB (timer, context) + + local evtinfo= AFB:timerget(timer) + print ("timer=", Dump_Table(evtinfo)) + + --send an event an event with count as value + AFB:evtpush (MyEventHandle, {["label"]= evtinfo["label"], ["count"]=evtinfo["count"], ["info"]=context["info"]}) + + -- note when timerCB return!=0 timer is kill + return 0 + +end + +-- sendback event depending on count and delay +function Simple_Timer_Test (request, args) + + local context = { + ["info"]="My 1st private Event", + } + + -- if delay not defined default is 5s + if (args["delay"]==nil) then args["delay"]=5000 end + + -- if count is not defined default is 10 + if (args["count"]==nil) then args["count"]=10 end + + -- we could use directly args but it is a sample + local myTimer = { + ["label"]=args["label"], + ["delay"]=args["delay"], + ["count"]=args["count"], + } + AFB:notice ("Test_Timer myTimer=%s", myTimer) + + -- subscribe to event + AFB:subscribe (request, MyEventHandle) + + -- settimer take a table with delay+count as input (count==0 means infinite) + AFB:timerset (myTimer, "Timer_Test_CB", context) + + -- nothing special to return send back args + AFB:success (request, myTimer) + + return 0 +end + + + diff --git a/htdocs/audio-control.html b/htdocs/audio-control.html index d51f527..d51ae55 100644 --- a/htdocs/audio-control.html +++ b/htdocs/audio-control.html @@ -32,6 +32,7 @@
  • +
  • diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index fb247d1..a5d9f8e 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -46,10 +46,10 @@ ctl-binding.c ctl-dispatch.c - ctl-events.c ctl-lua.c ctl-misc.c ctl-plugin-sample.c + ctl-timer.c @@ -147,39 +147,87 @@ ex="false" tool="0" flavor2="3"> - + - + + + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + - + + + build/Alsa-afb + - + + + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + - + + + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + - + + + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + - + + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + - - + + + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + - + + + Audio-Common + /usr/include/json-c + build/Audio-Common + @@ -218,37 +266,19 @@ - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + ../../../opt/include/afb + Controler-afb /usr/include/json-c /usr/include/lua5.3 Audio-Common + ../../../opt/include build/Controler-afb - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - control_afb_EXPORTS - - + ../../../opt/include @@ -279,94 +309,65 @@ - - + + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + ../../../opt/include/afb + Controler-afb /usr/include/json-c - /usr/include/lua5.3 - Audio-Common build/Controler-afb - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - control_afb_EXPORTS - - + ../../../opt/include/afb Controler-afb /usr/include/json-c + /usr/include/lua5.3 build/Controler-afb - - + + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + ../../../opt/include/afb + Controler-afb /usr/include/json-c - /usr/include/lua5.3 - Audio-Common + ../../../opt/include build/Controler-afb - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - audio_plugin_sample_EXPORTS - - + + + Audio-Common + build/HAL-afb/HAL-interface + - + + + Audio-Common + build/HAL-afb/HAL-interface + - + + + build/HAL-afb/HAL-interface + @@ -374,21 +375,21 @@ - + - + - + @@ -453,11 +454,11 @@ - ../../../opt/include + Alsa-Plugin/Alsa-Policy-Hook ../../../opt/include/alsa - /usr/include/p11-kit-1 /usr/include/json-c - /usr/include/lua5.3 + ../../../opt/include/afb + ../../../opt/include build/Alsa-Plugin/Alsa-Policy-Hook @@ -484,62 +485,9 @@ - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c - /usr/include/lua5.3 - Audio-Common - build/Alsa-afb - - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - alsa_lowlevel_EXPORTS - - - - - - - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c - /usr/include/lua5.3 - Audio-Common - build/Audio-Common + ../../../opt/include/afb + Alsa-afb - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - @@ -604,15 +552,9 @@ + ../../../opt/include/afb HAL-afb/HAL-interface - Audio-Common - build/HAL-afb/HAL-interface - - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_SUPPORT_LUA - NATIVE_LINUX - @@ -635,46 +577,34 @@ - HAL-afb/HAL-interface + ../../../opt/include/afb + HAL-afb/HDA-intel Audio-Common + HAL-afb/HAL-interface build/HAL-afb/HDA-intel - - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_SUPPORT_LUA - NATIVE_LINUX - hal_intel_hda_EXPORTS - - HAL-afb/HAL-interface + HAL-afb/Jabra-Solemate + ../../../opt/include/afb Audio-Common + HAL-afb/HAL-interface build/HAL-afb/Jabra-Solemate - - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_SUPPORT_LUA - NATIVE_LINUX - hal_jabra_usb_EXPORTS - - HAL-afb/HAL-interface + ../../../opt/include/afb + HAL-afb/Scarlett-Focusrite Audio-Common + HAL-afb/HAL-interface build/HAL-afb/Scarlett-Focusrite - - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_SUPPORT_LUA - NATIVE_LINUX - hal_scalett_usb_EXPORTS - @@ -1231,11 +1161,11 @@ - + - + @@ -1614,7 +1544,7 @@ - + Audio-Common @@ -1625,7 +1555,7 @@ - + Audio-Common @@ -1636,24 +1566,24 @@ - + - Audio-Common build/Controler-afb - control_afb_EXPORTS + audio_plugin_sample_EXPORTS - + + Audio-Common build/Controler-afb - audio_plugin_sample_EXPORTS + control_afb_EXPORTS -- cgit 1.2.3-korg From a7d41a6fa1e29d800ce8ac9e95e8f943814463e8 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Fri, 18 Aug 2017 01:09:56 +0200 Subject: Integration with Alsa HookPlugin is now working. --- Alsa-Plugin/Alsa-Policy-Hook/PolicyHookCb.c | 43 +- Alsa-Plugin/Alsa-Policy-Hook/README.md | 7 +- Alsa-afb/Alsa-ApiHat.c | 6 +- Audio-Common/filescan-utils.c | 4 +- Audio-Common/filescan-utils.h | 2 +- Controler-afb/CMakeLists.txt | 84 -- Controler-afb/README.md | 254 ----- Controler-afb/ctl-apidef.h | 129 --- Controler-afb/ctl-apidef.json | 281 ------ Controler-afb/ctl-binding.c | 65 -- Controler-afb/ctl-binding.h | 137 --- Controler-afb/ctl-dispatch.c | 643 ------------ Controler-afb/ctl-lua.c | 1026 ------------------- Controler-afb/ctl-plugin-sample.c | 134 --- Controler-afb/ctl-policy.c | 221 ----- Controler-afb/ctl-timer.c | 156 --- Controller-afb/CMakeLists.txt | 84 ++ Controller-afb/README.md | 333 +++++++ Controller-afb/a.out | Bin 0 -> 12552 bytes Controller-afb/ctl-apidef.h | 115 +++ Controller-afb/ctl-apidef.json | 250 +++++ Controller-afb/ctl-binding.c | 65 ++ Controller-afb/ctl-binding.h | 146 +++ Controller-afb/ctl-dispatch.c | 665 +++++++++++++ Controller-afb/ctl-lua.c | 1033 ++++++++++++++++++++ Controller-afb/ctl-plugin-sample.c | 134 +++ Controller-afb/ctl-policy.c | 221 +++++ Controller-afb/ctl-timer.c | 101 ++ HAL-afb/HAL-interface/hal-interface.c | 13 +- conf.d/alsa-sample/asoundrc.sample | 160 --- conf.d/alsa-sample/ucm.sample/HDA Intel PCH.conf | 6 - conf.d/alsa-sample/ucm.sample/HiFi.conf | 84 -- conf.d/alsa-sample/ucm.sample/README | 2 - conf.d/cmake/config.cmake | 8 +- conf.d/project/alsa.d/asoundrc.sample | 146 +++ .../project/alsa.d/ucm.sample/HDA Intel PCH.conf | 6 + conf.d/project/alsa.d/ucm.sample/HiFi.conf | 84 ++ conf.d/project/alsa.d/ucm.sample/README | 2 + conf.d/project/config.d/onload-audio-control.json | 14 +- conf.d/project/lua.d/doscript-helloworld.lua | 2 +- conf.d/project/lua.d/onload-audio-0utils.lua | 86 ++ conf.d/project/lua.d/onload-audio-controls.lua | 159 ++- conf.d/project/lua.d/onload-audio-oncall.lua | 16 +- conf.d/project/lua.d/onload-audio-timer.lua | 10 +- conf.d/project/lua.d/onload-audio-utils.lua | 32 - data/default-control-policy.json | 2 +- htdocs/AudioBinding.js | 1 - htdocs/alsa-hal.html | 16 +- htdocs/audio-control.html | 23 +- nbproject/configurations.xml | 933 +++++++++++++++--- nbproject/project.xml | 4 + 51 files changed, 4509 insertions(+), 3639 deletions(-) delete mode 100644 Controler-afb/CMakeLists.txt delete mode 100644 Controler-afb/README.md delete mode 100644 Controler-afb/ctl-apidef.h delete mode 100644 Controler-afb/ctl-apidef.json delete mode 100644 Controler-afb/ctl-binding.c delete mode 100644 Controler-afb/ctl-binding.h delete mode 100644 Controler-afb/ctl-dispatch.c delete mode 100644 Controler-afb/ctl-lua.c delete mode 100644 Controler-afb/ctl-plugin-sample.c delete mode 100644 Controler-afb/ctl-policy.c delete mode 100644 Controler-afb/ctl-timer.c create mode 100644 Controller-afb/CMakeLists.txt create mode 100644 Controller-afb/README.md create mode 100755 Controller-afb/a.out create mode 100644 Controller-afb/ctl-apidef.h create mode 100644 Controller-afb/ctl-apidef.json create mode 100644 Controller-afb/ctl-binding.c create mode 100644 Controller-afb/ctl-binding.h create mode 100644 Controller-afb/ctl-dispatch.c create mode 100644 Controller-afb/ctl-lua.c create mode 100644 Controller-afb/ctl-plugin-sample.c create mode 100644 Controller-afb/ctl-policy.c create mode 100644 Controller-afb/ctl-timer.c delete mode 100644 conf.d/alsa-sample/asoundrc.sample delete mode 100644 conf.d/alsa-sample/ucm.sample/HDA Intel PCH.conf delete mode 100644 conf.d/alsa-sample/ucm.sample/HiFi.conf delete mode 100644 conf.d/alsa-sample/ucm.sample/README create mode 100644 conf.d/project/alsa.d/asoundrc.sample create mode 100644 conf.d/project/alsa.d/ucm.sample/HDA Intel PCH.conf create mode 100644 conf.d/project/alsa.d/ucm.sample/HiFi.conf create mode 100644 conf.d/project/alsa.d/ucm.sample/README create mode 100644 conf.d/project/lua.d/onload-audio-0utils.lua delete mode 100644 conf.d/project/lua.d/onload-audio-utils.lua diff --git a/Alsa-Plugin/Alsa-Policy-Hook/PolicyHookCb.c b/Alsa-Plugin/Alsa-Policy-Hook/PolicyHookCb.c index 7c85e22..80a9ceb 100644 --- a/Alsa-Plugin/Alsa-Policy-Hook/PolicyHookCb.c +++ b/Alsa-Plugin/Alsa-Policy-Hook/PolicyHookCb.c @@ -53,11 +53,14 @@ #define MAX_EVT_CALL 10 // timeout in ms -#define REQUEST_DEFAULT_TIMEOUT 100 +#define REQUEST_DEFAULT_TIMEOUT 500 #ifndef MAINLOOP_WATCHDOG -#define MAINLOOP_WATCHDOG 60000 +#define MAINLOOP_WATCHDOG 100000 #endif +// closing message is added to query when PCM is closed +#define CLOSING_MSG ",\"source\":-1}" + // Currently not implemented #define UNUSED_ARG(x) UNUSED_ ## x __attribute__((__unused__)) void OnRequestCB(void* UNUSED_ARG(handle) , const char* UNUSED_ARG(api), const char* UNUSED_ARG(verb), struct afb_wsj1_msg*UNUSED_ARG(msg)) {} @@ -67,6 +70,7 @@ typedef struct { const char *verb; long timeout; char *query; + size_t length; sd_event_source *evtSource; char *callIdTag; @@ -101,7 +105,7 @@ static void *LoopInThread(void *handle) { /* loop until end */ for (;;) { - if (afbClient->verbose) printf("ON-MAINLOOP Active count=%d\n", count++); + if (afbClient->verbose) printf("ON-MAINLOOP ping=%d\n", count++); sd_event_run(afbClient->sdLoop, watchdog); } @@ -214,7 +218,6 @@ int OnTimeoutCB (sd_event_source* source, uint64_t timer, void* handle) { static int CallWithTimeout(afbClientT *afbClient, afbRequestT *afbRequest, int count, hookActionT action) { uint64_t usec; int err; - const char *query; // create a unique tag for request (void) asprintf(&afbRequest->callIdTag, "%d:%s/%s", count, afbRequest->api, afbRequest->verb); @@ -223,9 +226,19 @@ static int CallWithTimeout(afbClientT *afbClient, afbRequestT *afbRequest, int c sd_event_now(afbClient->sdLoop, CLOCK_MONOTONIC, &usec); sd_event_add_time(afbClient->sdLoop, &afbRequest->evtSource, CLOCK_MONOTONIC, usec+afbRequest->timeout*1000, 250, OnTimeoutCB, afbClient); - if (action == HOOK_INSTALL) query=afbRequest->query; - else query="{'closing': 1}"; - err = afb_wsj1_call_s(afbClient->wsj1, afbRequest->api, afbRequest->verb, query, OnResponseCB, afbRequest); + if (afbClient->verbose) printf("CALL-REQUEST api=%s/%s tag=%s\n", afbRequest->api, afbRequest->verb, afbRequest->callIdTag); + + // on PCM close replace last '}' by CLOSING_MSG + if (action == HOOK_CLOSE) { + for (size_t index=afbRequest->length; index >0; index--) { + if (afbRequest->query[index] == '}') { + strcpy (&afbRequest->query[index], CLOSING_MSG); + break; + } + } + } + + err = afb_wsj1_call_s(afbClient->wsj1, afbRequest->api, afbRequest->verb, afbRequest->query, OnResponseCB, afbRequest); if (err) goto OnErrorExit; // save client handle in request @@ -421,18 +434,22 @@ int PLUGIN_ENTRY_POINT (snd_pcm_t *pcm, snd_config_t *conf) { if (!err) { const char *query; if (snd_config_get_string(itemConf, &query) < 0) { - SNDERR("Invalid query string %s", id); + SNDERR("Invalid args string %s", id); goto OnErrorExit; } + // reserve enough space to ad closing message + afbRequest[callCount]->length= strlen(query); + afbRequest[callCount]->query = malloc (afbRequest[callCount]->length+strlen(CLOSING_MSG)+1); + strcpy (afbRequest[callCount]->query, query); + // cleanup string for json_tokener - afbRequest[callCount]->query = strdup(query); for (int idx = 0; query[idx] != '\0'; idx++) { if (query[idx] == '\'') afbRequest[callCount]->query[idx] = '"'; else afbRequest[callCount]->query[idx] = query[idx]; } - json_object *queryJ = json_tokener_parse(query); + json_object *queryJ = json_tokener_parse(afbRequest[callCount]->query); if (!queryJ) { - SNDERR("Invalid Json %s query=%s format \"{'tok1':'val1', 'tok2':'val2'}\" ", id, query); + SNDERR("Invalid Json %s args=%s should be args=\"{'tok1':'val1', 'tok2':'val2'}\" ", id, afbRequest[callCount]->query); goto OnErrorExit; } } @@ -520,7 +537,7 @@ int PLUGIN_ENTRY_POINT (snd_pcm_t *pcm, snd_config_t *conf) { // wait for all call request to return sem_wait(&afbClient->semaphore); if (afbClient->error) { - fprintf (stderr, "PCM Authorisation from Audio Agent Refused\n"); + fprintf (stderr, "PCM Authorisation Deny from AAAA Controller (AGL Advanced Audio Agent)\n"); goto OnErrorExit; } @@ -528,7 +545,7 @@ int PLUGIN_ENTRY_POINT (snd_pcm_t *pcm, snd_config_t *conf) { return 0; OnErrorExit: - fprintf(stderr, "\nAlsaPcmHook Plugin Install Fail PCM=%s\n", snd_pcm_name(afbClient->pcm)); + fprintf(stderr, "\nAlsaPcmHook Plugin Install Fail PCM=%s\n", snd_pcm_name(pcm)); if (h_close) snd_pcm_hook_remove(h_close); diff --git a/Alsa-Plugin/Alsa-Policy-Hook/README.md b/Alsa-Plugin/Alsa-Policy-Hook/README.md index 8fa2643..6a8e67e 100644 --- a/Alsa-Plugin/Alsa-Policy-Hook/README.md +++ b/Alsa-Plugin/Alsa-Policy-Hook/README.md @@ -14,6 +14,10 @@ Installation - This plugin implement a hook on a slave PCM. Typically this slave PCM is a dedicated virtual channel (eg: navigation, emergency,...) - Config should be place in ~/.asoundrc (see config sample in PROJECT_ROOT/conf.d/alsa) +Test + - Install a full .asoundrc from conf.d/project/alsa.d + - speaker-test -DMyNavigationHook -c2 -twav + Config ``` # Define sharelib location and entry point @@ -42,8 +46,7 @@ pcm.MyNavigationHook { navigation-ctl { api "control" verb "dispatch" - target "navigation" - args "{'any_valid': 'json object'}" + args "{'target':'navigation', 'args':{'device':'Jabra SOLEMATE v1.34.0'}}" } # subscribe to Audio Agent Event map them to signal subscribe-evt { diff --git a/Alsa-afb/Alsa-ApiHat.c b/Alsa-afb/Alsa-ApiHat.c index 1e9f5ad..a8663ca 100644 --- a/Alsa-afb/Alsa-ApiHat.c +++ b/Alsa-afb/Alsa-ApiHat.c @@ -31,7 +31,7 @@ #include "Alsa-ApiHat.h" STATIC int AlsaInit(void) { - int rc= prctl(PR_SET_NAME, "afb-audio-agent\0",NULL,NULL,NULL); + int rc= prctl(PR_SET_NAME, "afb-audio-agent",NULL,NULL,NULL); if (rc) AFB_ERROR("ERROR: AlsaCore fail to rename process"); return rc; @@ -62,8 +62,8 @@ static const struct afb_verb_v2 api_verbs[] = { /* * description of the binding for afb-daemon */ -const struct afb_binding_v2 afbBindingV2 = { +const afb_binding_v2 afbBindingV2 = { .api = "alsacore", .verbs = api_verbs, - .init = AlsaInit, + .preinit = AlsaInit, }; diff --git a/Audio-Common/filescan-utils.c b/Audio-Common/filescan-utils.c index 33dacdf..af0b5c9 100644 --- a/Audio-Common/filescan-utils.c +++ b/Audio-Common/filescan-utils.c @@ -27,7 +27,7 @@ // List Avaliable Configuration Files -PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, const char *pre, const char *ext) { +PUBLIC json_object* ScanForConfig (const char* searchPath, CtlScanDirModeT mode, const char *pre, const char *ext) { json_object *responseJ; char *dirPath; char* dirList= strdup(searchPath); @@ -94,7 +94,7 @@ PUBLIC const char *GetMidleName(const char*name) { int start; if (fullname[idx] == '-') { start = idx + 1; - for (int jdx = start; fullname[jdx] != '\0'; jdx++) { + for (int jdx = start; ; jdx++) { if (fullname[jdx] == '-' || fullname[jdx] == '.' || fullname[jdx] == '\0') { fullname[jdx] = '\0'; return &fullname[start]; diff --git a/Audio-Common/filescan-utils.h b/Audio-Common/filescan-utils.h index 671e728..cbe15de 100644 --- a/Audio-Common/filescan-utils.h +++ b/Audio-Common/filescan-utils.h @@ -35,7 +35,7 @@ typedef enum { PUBLIC const char *GetMidleName(const char*name); PUBLIC const char *GetBinderName(); -PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, const char *pre, const char *ext); +PUBLIC json_object* ScanForConfig (const char* searchPath, CtlScanDirModeT mode, const char *pre, const char *ext); #endif /* FILESCAN_UTILS_H */ diff --git a/Controler-afb/CMakeLists.txt b/Controler-afb/CMakeLists.txt deleted file mode 100644 index a9e8e60..0000000 --- a/Controler-afb/CMakeLists.txt +++ /dev/null @@ -1,84 +0,0 @@ -########################################################################### -# Copyright 2015, 2016, 2017 IoT.bzh -# -# author: Fulup Ar Foll -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -########################################################################### - - -# Generate API-v2 hat from OpenAPI json definition -macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME) - add_custom_command(OUTPUT ${API_DEF_NAME}.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${API_DEF_NAME}.json - COMMAND afb-genskel ${API_DEF_NAME}.json >${API_DEF_NAME}.h - ) - add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h) - add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI) -endmacro(SET_TARGET_GENSKEL) - -# Include LUA only when requested -if(CONTROL_SUPPORT_LUA) - message(STATUS "Notice: LUA Controler Support Selected") - set(CTL_LUA_SOURCE ctl-lua.c) -endif(CONTROL_SUPPORT_LUA) - -# Add target to project dependency list -PROJECT_TARGET_ADD(control-afb) - - # Define project Targets - ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-timer.c ctl-dispatch.c ${CTL_LUA_SOURCE}) - - # Generate API-v2 hat from OpenAPI json definition - SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) - - # Binder exposes a unique public entry point - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX "afb-" - LABELS "BINDING" - LINK_FLAGS ${BINDINGS_LINK_FLAG} - OUTPUT_NAME ${TARGET_NAME} - ) - - # Library dependencies (include updates automatically) - TARGET_LINK_LIBRARIES(${TARGET_NAME} - audio-common - ${link_libraries} - ) - - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION CMAKE_INSTALL_PREFIX ) - -PROJECT_TARGET_ADD(audio-plugin-sample) - - # Define targets - ADD_LIBRARY(${TARGET_NAME} MODULE ctl-plugin-sample.c) - - # Alsa Plugin properties - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX ${CTL_PLUGIN_PRE} - SUFFIX ${CTL_PLUGIN_EXT} - OUTPUT_NAME ${TARGET_NAME} - ) - - # Library dependencies (include updates automatically) - TARGET_LINK_LIBRARIES(${TARGET_NAME} - audio-common - ${link_libraries} - ) - - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}/controler) diff --git a/Controler-afb/README.md b/Controler-afb/README.md deleted file mode 100644 index a81d4f7..0000000 --- a/Controler-afb/README.md +++ /dev/null @@ -1,254 +0,0 @@ -Controler AAAA(AGL Advance Audio Controler) and more. ------------------------------------------------------------- - - * Object: Generic Controler to handle Policy,Small Business Logic, Glue in between components, ... - * Status: Release Candidate - * Author: Fulup Ar Foll fulup@iot.bzh - * Date : August-2017 - -## Functionalities: - - Create an application dedicate controller from a JSON config file - - Each controls (eg: navigation, multimedia, ...) is a suite of actions. When all actions succeed control is granted, if one fail control acces is denied. - - Actions can either be: - + Invocation to an other binding API, either internal or external (eg: a policy service, Alsa UCM, ...) - + C routines from a user provider plugin (eg: policy routine, proprietary code, ...) - + Lua script function. Lua provides access to every AGL appfw functionalities and can be extended from C user provided plugins. - -## Installation - - Controler is a native part of AGL Advance Audio Framework but may be used independently with any other service or application binder. - - Dependencies: the only dependencies are audio-common for JSON-WRAP and Filescan-utils capabilities. - - Controler relies on Lua-5.3, when not needed Lua might be removed at compilation time. - -## Config - -Configuration is loaded dynamically during startup time. The controller scans CONTROL_CONFIG_PATH for a file corresponding to pattern -"onload-bindername-xxxxx.json". When controller runs within AAAA binder it searches for "onload-audio-xxxx.json". First file found in the path the loaded -any other files corresponding to the same pather are ignored and only generate a warning. - -Each bloc in the configuration file are defined with - * label: must be provided is used either for debugging or as input for the action (eg: signal name, control name, ...) - * info: optional used for documentation purpose only - -### Config is organised in 4 sections: - - * metadata - * onload defines the set of action to be executed at startup time - * control defines the set of controls with corresponding actions - * event define the set of actions to be executed when receiving a given signal - -### Metadata - -As today matadata is only used for documentation purpose. - * label + version mandatory - * info optional - -### OnLoad section - -Defines startup time configuration. Onload may provide multiple initialisation profiles, each with a different label. - * label is mandatory. Label is used to select onload profile at initialisation through DispatchOneOnLoad("onload-label") API; - * info is optional - * plugin provides optional unique plugin name. Plugin should follow "onload-bindername-xxxxx.ctlso" patern - and are search into CONTROL_PLUGIN_PATH. When defined controller will execute user provided function context=CTLP_ONLOAD(label,version,info). - The context returned by this routine is provided back to any C routines call later by the controller. Note that Lua2C function - are prefix in Lua script with plugin label (eg: MyPlug: in following config sample) - * lua2c list of Lua commands shipped with provided plugin. - * require list of binding that should be initialised before the controller starts. Note that some listed requirer binding might be absent, - nevertheless any present binding from this list will be started before controller binding, missing ones generate a warning. - * action the list of action to execute during loadtime. Any failure in action will prevent controller binding from starting. - -### Control section - -Defines a list of controls that are accessible through (api="control", verb="request", control="control-label"). - - * label mandatory - * info optional - * permissions Cynara needed privileges to request this control (same as AppFw-V2) - * action the list of actions - -### Event section - -Defines a list of actions to be executed on event reception. Even can do anything a controller can (change state, -send back signal, ...) eg: if a controller subscribes to vehicule speed, then speed-event may ajust master-volume to speed. - - * label mandatory - * info optional - * action the list of actions - -### Actions Categories - -Controler support tree categories of actions. Each action return a status status where 0=success and 1=failure. - * AppFw API, Provides a generic model to request other bindings. Requested binding can be local (eg: ALSA/UCM) or - external (eg: vehicle signalling). - * api provides requested binding API name - * verb provides verb to requested binding - * args optionally provides a jsonc object for targeted binding API. Note that 'args' are statically defined - in JSON configuration file. Controler client may also provided its own arguments from the query list. Targeted - binding receives both arguments defined in the config file and the argument provided by controller client. - * C-API, when defined in the onload section, the plugin may provided C native API with CTLP-CAPI(apiname, label, args, query, context). - Plugin may also create Lua command with CTLP-Lua2C(LuaFuncName, label, args, query, context). Where args+query are JSONC object - and context the value return from CTLP_ONLOAD function. Any missing value is set to NULL. - * Lua-API, when compiled with Lua option, the controller support action defined directly in Lua script. During "onload" phase the - controller search in CONTROL_Lua_PATH file with pattern "onload-bindername-xxxx.lua". Any file corresponding to this pattern - is automatically loaded. Any function defined in those Lua script can be called through a controller action. Lua functions receive - three parameters (label, args, query). - -Note: Lua added functions systematically prefix. AGL standard AppFw functions are prefixed with AGL: (eg: AGL:notice(), AGL_success(), ...). -User Lua functions added though the plugin and CTLP_Lua2C are prefix with plugin label (eg: MyPlug:HelloWorld1). - -### Debugging Facilities - -Controler Lua script are check for syntax from CMAKE template with Luac. When needed to go further an developer API allow to -execute directly Lua command within controller context from Rest/Ws (api=control, verb=lua_doscript). DoScript API takes two -other optional arguments func=xxxx where xxxx is the function to execute within Lua script and args a JSON object to provide -input parameter. When funcname is not given by default the controller try to execute middle filename doscript-xxxx-????.lua. - -When executed from controller Lua script may use any AppFw Apis as well as any L2C user defined commands in plugin. - -## Config Sample - -Here after a simple configuration sample. - -``` -{ - "$schema": "ToBeDone", - "metadata": { - "label": "sample-audio-control", - "info": "Provide Default Audio Policy for Multimedia, Navigation and Emergency", - "version": "1.0" - }, - "onload": [{ - "label": "onload-default", - "info": "onload initialisation config", - "plugin": { - "label" : "MyPlug", - "sharelib": "ctl-audio-plugin-sample.ctlso", - "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] - }, - "require": ["intel-hda", "jabra-usb", "scarlett-usb"], - "actions": [ - { - "label": "onload-sample-cb", - "info": "Call control sharelib install entrypoint", - "callback": "SamplePolicyInit", - "args": { - "arg1": "first_arg", - "nextarg": "second arg value" - } - }, { - "label": "onload-sample-api", - "info": "Assert AlsaCore Presence", - "api": "alsacore", - "verb": "ping", - "args": "test" - }, { - "label": "onload-hal-lua", - "info": "Load avaliable HALs", - "lua": "Audio_Init_Hal" - } - ] - }], - "controls": - [ - { - "label": "multimedia", - "permissions": "urn:AGL:permission:audio:public:mutimedia", - "actions": { - "label": "multimedia-control-lua", - "info": "Call Lua Script function Test_Lua_Engin", - "lua": "Audio_Set_Multimedia" - } - }, { - "label": "navigation", - "permissions": "urn:AGL:permission:audio:public:navigation", - "actions": { - "label": "navigation-control-lua", - "info": "Call Lua Script to set Navigation", - "lua": "Audio_Set_Navigation" - } - }, { - "label": "emergency", - "permissions": "urn:AGL:permission:audio:public:emergency", - "actions": { - "label": "emergency-control-ucm", - "lua": "Audio_Set_Emergency" - } - }, { - "label": "multi-step-sample", - "info" : "all actions must succeed for control to be accepted", - "actions": [{ - "label": "multimedia-control-cb", - "info": "Call Sharelib Sample Callback", - "callback": "sampleControlNavigation", - "args": { - "arg1": "snoopy", - "arg2": "toto" - } - }, { - "label": "navigation-control-ucm", - "api": "alsacore", - "verb": "ping", - "args": { - "test": "navigation" - } - }, { - "label": "navigation-control-lua", - "info": "Call Lua Script to set Navigation", - "lua": "Audio_Set_Navigation" - }] - } - ], - "events": - [ - { - "label": "Vehicle-Speed", - "info": "Action when Vehicule speed change", - "actions": [ - { - "label": "speed-action-1", - "callback": "Blink-when-over-130", - "args": { - "speed": 130 - "blink-speed": 1000 - } - }, { - "label": "Adjust-Volume", - "lua": "Adjust_Volume_To_Speed", - } - ] - }, - { - "label": "Reverse-Engage", - "info": "When Reverse Gear is Engage", - "actions": [ - { - "label": "Display-Rear-Camera", - "callback": "Display-Rear-Camera", - }, { - "label": "Prevent-Phone-Call", - "api" : "phone", - "verb" : "status", - "args": { - "call-accepted": false - } - } - ] - }, - { - "label": "Neutral-Engage", - "info": "When Reverse Neutral is Engage", - "actions": [ - { - "label": "Authorize-Video", - "api" : "video", - "verb" : "status", - "args": { - "tv-accepted": true - } - } - ] - } - ] -} - -``` - diff --git a/Controler-afb/ctl-apidef.h b/Controler-afb/ctl-apidef.h deleted file mode 100644 index 848fd14..0000000 --- a/Controler-afb/ctl-apidef.h +++ /dev/null @@ -1,129 +0,0 @@ - -static const char _afb_description_v2_control[] = - "{\"openapi\":\"3.0.0\",\"$schema\":\"http:iot.bzh/download/openapi/schem" - "a-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\"c" - "ontroler\",\"version\":\"1.0\",\"x-binding-c-generator\":{\"api\":\"cont" - "rol\",\"version\":2,\"prefix\":\"ctlapi_\",\"postfix\":\"\",\"start\":nu" - "ll,\"onevent\":\"DispatchOneEvent\",\"init\":\"CtlBindingInit\",\"scope\"" - ":\"\",\"private\":false}},\"servers\":[{\"url\":\"ws://{host}:{port}/api" - "/polctl\",\"description\":\"Unicens2 API.\",\"variables\":{\"host\":{\"d" - "efault\":\"localhost\"},\"port\":{\"default\":\"1234\"}},\"x-afb-events\"" - ":[{\"$ref\":\"#/components/schemas/afb-event\"}]}],\"components\":{\"sch" - "emas\":{\"afb-reply\":{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\"" - "afb-event\":{\"$ref\":\"#/components/schemas/afb-event-v2\"},\"afb-reply" - "-v2\":{\"title\":\"Generic response.\",\"type\":\"object\",\"required\":" - "[\"jtype\",\"request\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"" - "const\":\"afb-reply\"},\"request\":{\"type\":\"object\",\"required\":[\"" - "status\"],\"properties\":{\"status\":{\"type\":\"string\"},\"info\":{\"t" - "ype\":\"string\"},\"token\":{\"type\":\"string\"},\"uuid\":{\"type\":\"s" - "tring\"},\"reqid\":{\"type\":\"string\"}}},\"response\":{\"type\":\"obje" - "ct\"}}},\"afb-event-v2\":{\"type\":\"object\",\"required\":[\"jtype\",\"" - "event\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-" - "event\"},\"event\":{\"type\":\"string\"},\"data\":{\"type\":\"object\"}}" - "}},\"x-permissions\":{\"monitor\":{\"permission\":\"urn:AGL:permission:a" - "udio:public:monitor\"},\"multimedia\":{\"permission\":\"urn:AGL:permissi" - "on:audio:public:monitor\"},\"navigation\":{\"permission\":\"urn:AGL:perm" - "ission:audio:public:monitor\"},\"emergency\":{\"permission\":\"urn:AGL:p" - "ermission:audio:public:emergency\"}},\"responses\":{\"200\":{\"descripti" - "on\":\"A complex object array response\",\"content\":{\"application/json" - "\":{\"schema\":{\"$ref\":\"#/components/schemas/afb-reply\"}}}}}},\"path" - "s\":{\"/monitor\":{\"description\":\"Subcribe Audio Agent Policy Control" - " End\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions" - "/monitor\"},\"parameters\":[{\"in\":\"query\",\"name\":\"event_patern\"," - "\"required\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"20" - "0\":{\"$ref\":\"#/components/responses/200\"}}}},\"/timer_test\":{\"desc" - "ription\":\"Pause Resume Test\",\"get\":{\"x-permissions\":{\"$ref\":\"#" - "/components/x-permissions/monitor\"},\"parameters\":[{\"in\":\"query\",\"" - "name\":\"delay\",\"required\":false,\"schema\":{\"type\":\"interger\"}}," - "{\"in\":\"query\",\"name\":\"count\",\"required\":false,\"schema\":{\"ty" - "pe\":\"interger\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/res" - "ponses/200\"}}}},\"/dispatch\":{\"description\":\"Request Access to Navi" - "gation Audio Channel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/compone" - "nts/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"name" - "\":\"zone\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"resp" - "onses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_doc" - "all\":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-permi" - "ssions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"paramete" - "rs\":[{\"in\":\"query\",\"name\":\"func\",\"required\":true,\"schema\":{" - "\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"args\",\"required\":f" - "alse,\"schema\":{\"type\":\"array\"}}],\"responses\":{\"200\":{\"$ref\":" - "\"#/components/responses/200\"}}}},\"/lua_dostring\":{\"description\":\"" - "Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/co" - "mponents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"" - "required\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\"" - ":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_doscript\":{\"descr" - "iption\":\"Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$r" - "ef\":\"#/components/x-permissions/navigation\"},\"parameters\":[{\"in\":" - "\"query\",\"name\":\"filename\",\"required\":true,\"schema\":{\"type\":\"" - "string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/20" - "0\"}}}}}}" -; - -static const struct afb_auth _afb_auths_v2_control[] = { - { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:monitor" } -}; - - void ctlapi_monitor(struct afb_req req); - void ctlapi_timer_test(struct afb_req req); - void ctlapi_dispatch(struct afb_req req); - void ctlapi_lua_docall(struct afb_req req); - void ctlapi_lua_dostring(struct afb_req req); - void ctlapi_lua_doscript(struct afb_req req); - -static const struct afb_verb_v2 _afb_verbs_v2_control[] = { - { - .verb = "monitor", - .callback = ctlapi_monitor, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "timer_test", - .callback = ctlapi_timer_test, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "dispatch", - .callback = ctlapi_dispatch, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "lua_docall", - .callback = ctlapi_lua_docall, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "lua_dostring", - .callback = ctlapi_lua_dostring, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "lua_doscript", - .callback = ctlapi_lua_doscript, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { .verb = NULL } -}; - -const struct afb_binding_v2 afbBindingV2 = { - .api = "control", - .specification = _afb_description_v2_control, - .info = NULL, - .verbs = _afb_verbs_v2_control, - .preinit = NULL, - .init = CtlBindingInit, - .onevent = DispatchOneEvent, - .noconcurrency = 0 -}; - diff --git a/Controler-afb/ctl-apidef.json b/Controler-afb/ctl-apidef.json deleted file mode 100644 index 621fd5e..0000000 --- a/Controler-afb/ctl-apidef.json +++ /dev/null @@ -1,281 +0,0 @@ -{ - "openapi": "3.0.0", - "$schema": "http:iot.bzh/download/openapi/schema-3.0/default-schema.json", - "info": { - "description": "", - "title": "controler", - "version": "1.0", - "x-binding-c-generator": { - "api": "control", - "version": 2, - "prefix": "ctlapi_", - "postfix": "", - "start": null, - "onevent": "DispatchOneEvent", - "init": "CtlBindingInit", - "scope": "", - "private": false - } - }, - "servers": [ - { - "url": "ws://{host}:{port}/api/polctl", - "description": "Unicens2 API.", - "variables": { - "host": { - "default": "localhost" - }, - "port": { - "default": "1234" - } - }, - "x-afb-events": [ - { - "$ref": "#/components/schemas/afb-event" - } - ] - } - ], - "components": { - "schemas": { - "afb-reply": { - "$ref": "#/components/schemas/afb-reply-v2" - }, - "afb-event": { - "$ref": "#/components/schemas/afb-event-v2" - }, - "afb-reply-v2": { - "title": "Generic response.", - "type": "object", - "required": ["jtype", "request"], - "properties": { - "jtype": { - "type": "string", - "const": "afb-reply" - }, - "request": { - "type": "object", - "required": ["status"], - "properties": { - "status": { - "type": "string" - }, - "info": { - "type": "string" - }, - "token": { - "type": "string" - }, - "uuid": { - "type": "string" - }, - "reqid": { - "type": "string" - } - } - }, - "response": { - "type": "object" - } - } - }, - "afb-event-v2": { - "type": "object", - "required": ["jtype", "event"], - "properties": { - "jtype": { - "type": "string", - "const": "afb-event" - }, - "event": { - "type": "string" - }, - "data": { - "type": "object" - } - } - } - }, - "x-permissions": { - "monitor": { - "permission": "urn:AGL:permission:audio:public:monitor" - }, - "multimedia": { - "permission": "urn:AGL:permission:audio:public:monitor" - }, - "navigation": { - "permission": "urn:AGL:permission:audio:public:monitor" - }, - "emergency": { - "permission": "urn:AGL:permission:audio:public:emergency" - } - }, - "responses": { - "200": { - "description": "A complex object array response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/afb-reply" - } - } - } - } - } - }, - "paths": { - "/monitor": { - "description": "Subcribe Audio Agent Policy Control End", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/monitor" - }, - "parameters": [ - { - "in": "query", - "name": "event_patern", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/timer_test": { - "description": "Pause Resume Test", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/monitor" - }, - "parameters": [ - { - "in": "query", - "name": "delay", - "required": false, - "schema": { - "type": "interger" - } - }, - { - "in": "query", - "name": "count", - "required": false, - "schema": { - "type": "interger" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/dispatch": { - "description": "Request Access to Navigation Audio Channel.", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/navigation" - }, - "parameters": [ - { - "in": "query", - "name": "zone", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/lua_docall": { - "description": "Execute LUA string script.", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/navigation" - }, - "parameters": [ - { - "in": "query", - "name": "func", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "args", - "required": false, - "schema": { - "type": "array" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/lua_dostring": { - "description": "Execute LUA string script.", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/navigation" - }, - "parameters": [ - { - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/lua_doscript": { - "description": "Execute LUA string script.", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/navigation" - }, - "parameters": [ - { - "in": "query", - "name": "filename", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - } - } -} diff --git a/Controler-afb/ctl-binding.c b/Controler-afb/ctl-binding.c deleted file mode 100644 index 8771fc0..0000000 --- a/Controler-afb/ctl-binding.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include -#include - -#include "audio-common.h" -#include "ctl-binding.h" - - - -// Include Binding Stub generated from Json OpenAPI -#include "ctl-apidef.h" - - -PUBLIC void ctlapi_monitor (afb_req request) { - - // subscribe Client to event - int err = afb_req_subscribe(request, TimerEvtGet()); - if (err != 0) { - afb_req_fail_f(request, "register-event", "Fail to subscribe binder event"); - goto OnErrorExit; - } - - afb_req_success(request, NULL, NULL); - - OnErrorExit: - return; -} - -// Create Binding Event at Init -PUBLIC int CtlBindingInit () { - - int errcount=0; - - errcount += TimerEvtInit(); - errcount += DispatchInit(); -#ifdef CONTROL_SUPPORT_LUA - errcount += LuaLibInit(); -#endif - - // now that everything is initialised execute the onload action - if (!errcount) - errcount += DispatchOnLoad(CONTROL_ONLOAD_DEFAULT); - - AFB_DEBUG ("Audio Policy Control Binding Done errcount=%d", errcount); - return errcount; -} - diff --git a/Controler-afb/ctl-binding.h b/Controler-afb/ctl-binding.h deleted file mode 100644 index c998007..0000000 --- a/Controler-afb/ctl-binding.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CONTROLER_BINDING_INCLUDE -#define CONTROLER_BINDING_INCLUDE - -#define AFB_BINDING_VERSION 2 -#include -#include -#include -#include -#include - - -#ifdef CONTROL_SUPPORT_LUA -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" -#endif - -#ifndef PUBLIC - #define PUBLIC -#endif -#define STATIC static - -#ifndef UNUSED_ARG -#define UNUSED_ARG(x) UNUSED_ ## x __attribute__((__unused__)) -#define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x -#endif - -// polctl-binding.c -PUBLIC int CtlBindingInit (); - -// ctl-timerevt.c -// ---------------------- -typedef int (*timerCallbackT)(void *context); - -typedef struct TimerHandleS { - int count; - int delay; - const char*label; - void *context; - timerCallbackT callback; - sd_event_source *evtSource; -} TimerHandleT; - -PUBLIC int TimerEvtInit (void); -PUBLIC afb_event TimerEvtGet(void); -PUBLIC void ctlapi_event_test (afb_req request); -PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context); -PUBLIC void TimerEvtStop(TimerHandleT *timerHandle); - -// ctl-policy -// ----------- - -typedef enum { - CTL_MODE_NONE=0, - CTL_MODE_API, - CTL_MODE_CB, - CTL_MODE_LUA, -} CtlRequestModeT; - -typedef struct DispatchActionS{ - const char *info; - const char* label; - CtlRequestModeT mode; - const char* api; - const char* call; - json_object *argsJ; - int timeout; - int (*actionCB)(const char*label, json_object *argsJ, json_object *queryJ, void *context); -} DispatchActionT; -typedef int (*Lua2cFunctionT)(char *funcname, json_object *argsJ, void*context); - -PUBLIC int DispatchInit(void); -PUBLIC int DispatchOnLoad(const char *onLoadLabel); -PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ); -PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback); -PUBLIC void ctlapi_dispatch (afb_req request); - -#ifdef CONTROL_SUPPORT_LUA -// ctl-lua.c -typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunctionT callback); - -#define CTLP_LUA2C(FuncName,label,argsJ, context) static int FuncName(char*label,json_object*argsJ, void*context);\ - int lua2c_ ## FuncName(lua_State* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(FuncName), FuncName));};\ - static int FuncName(char* label, json_object* argsJ, void* context) - -typedef enum { - LUA_DOCALL, - LUA_DOSTRING, - LUA_DOSCRIPT, -} LuaDoActionT; - -PUBLIC int LuaLibInit (); -PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count); -PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context); -PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ); -PUBLIC void ctlapi_lua_docall (afb_req request); -PUBLIC void ctlapi_lua_dostring (afb_req request); -PUBLIC void ctlapi_lua_doscript (afb_req request); - -#else - typedef void* Lua2cWrapperT; -#endif // CONTROL_SUPPORT_LUA - - -// sharelib ctl-plugin* -typedef struct { - long magic; - char *label; -} CtlPluginMagicT; - - -#define MACRO_STR_VALUE(arg) #arg -#define CTLP_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; Lua2cWrapperT Lua2cWrap; -#define CTLP_ONLOAD(label,version,info) void* CtlPluginOnload(char* label, char* version, char* info) -#define CTLP_CAPI(funcname,label,argsJ, queryJ, context) int funcname(char* label, json_object* argsJ, json_object* queryJ, void* context) - - - -#endif // CONTROLER_BINDING_INCLUDE diff --git a/Controler-afb/ctl-dispatch.c b/Controler-afb/ctl-dispatch.c deleted file mode 100644 index 1afb846..0000000 --- a/Controler-afb/ctl-dispatch.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, something express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Reference: - * Json load using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values - */ - -#define _GNU_SOURCE -#include -#include -#include - -#include "ctl-binding.h" - -typedef void*(*DispatchPluginInstallCbT)(const char* label, const char*version, const char*info); - -static afb_req NULL_AFBREQ = {}; - -typedef enum { - CTL_DISPATCH_ONLOAD, - CTL_DISPATCH_CONTROL, - CTL_DISPATCH_EVENT, -} DispatchClassT; - -typedef struct { - const char* label; - const char *info; - DispatchActionT *actions; -} DispatchHandleT; - -typedef struct { - const char *label; - const char *info; - void *context; - char *sharelib; - void *dlHandle; - luaL_Reg *l2cFunc; - int l2cCount; -} DispatchPluginT; - -typedef struct { - const char* label; - const char *info; - const char *version; - DispatchPluginT *plugin; - DispatchHandleT **onloads; - DispatchHandleT **events; - DispatchHandleT **controls; -} DispatchConfigT; - -// global config handle -STATIC DispatchConfigT *configHandle = NULL; - -STATIC int DispatchControlToIndex(DispatchHandleT **controls, const char* controlLabel) { - - for (int idx = 0; controls[idx]; idx++) { - if (!strcasecmp(controlLabel, controls[idx]->label)) return idx; - } - return -1; -} - -STATIC int DispatchOneControl(DispatchHandleT **controls, const char* controlLabel, json_object *queryJ, afb_req request) { - int err; - - if (!configHandle) { - AFB_ERROR("DISPATCH-CTL-API: (Hoops/Bug!!!) No Config Loaded"); - goto OnErrorExit; - } - - if (!configHandle->controls) { - AFB_ERROR("DISPATCH-CTL-API: No Control Action in Json config label=%s version=%s", configHandle->label, configHandle->version); - goto OnErrorExit; - } - - int index = DispatchControlToIndex(controls, controlLabel); - if (index < 0 || !controls[index]->actions) { - AFB_ERROR("DISPATCH-CTL-API:NotFound/Error label=%s in Json Control Config File", controlLabel); - goto OnErrorExit; - } - - // Fulup (Bug/Feature) in current version is unique to every onload profile - if (configHandle->plugin && configHandle->plugin->l2cCount) { - LuaL2cNewLib (configHandle->plugin->label, configHandle->plugin->l2cFunc, configHandle->plugin->l2cCount); - } - - // loop on action for this control - DispatchActionT *actions = controls[index]->actions; - for (int idx = 0; actions[idx].label; idx++) { - - switch (actions[idx].mode) { - case CTL_MODE_API: - { - json_object *returnJ; - - json_object_get(actions[idx].argsJ); // make sure afb_service_call does not free the argsJ - int err = afb_service_call_sync(actions[idx].api, actions[idx].call, actions[idx].argsJ, &returnJ); - if (err) { - static const char*format = "DispatchOneControl(Api) api=%s verb=%s args=%s"; - if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:API", format, actions[idx].label, actions[idx].api, actions[idx].call); - else AFB_ERROR(format, actions[idx].api, actions[idx].call, actions[idx].label); - goto OnErrorExit; - } - break; - } - -#ifdef CONTROL_SUPPORT_LUA - case CTL_MODE_LUA: - err = LuaCallFunc(&actions[idx], queryJ); - if (err) { - static const char*format = "DispatchOneControl(Lua) label=%s func=%s args=%s"; - if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Lua", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); - else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); - goto OnErrorExit; - } - break; -#endif - - case CTL_MODE_CB: - err = (*actions[idx].actionCB) (actions[idx].label, actions[idx].argsJ, queryJ, configHandle->plugin->context); - if (err) { - static const char*format = "DispatchOneControl(Callback) label%s func=%s args=%s"; - if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Cb", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); - else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); - goto OnErrorExit; - } - break; - - default: - { - static const char*format = "DispatchOneControl(unknown) mode control=%s action=%s"; - AFB_ERROR(format, controls[index]->label); - if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:Unknown", format, controls[index]->label); - } - } - } - - // everything when fine - if (afb_req_is_valid(request))afb_req_success(request, NULL, controls[index]->label); - return 0; - -OnErrorExit: - return -1; -} - - -// Event name is mapped on control label and executed as a standard control - -PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ) { - DispatchHandleT **events = configHandle->events; - - (void) DispatchOneControl(events, evtLabel, eventJ, NULL_AFBREQ); -} - -// Event name is mapped on control label and executed as a standard control - -PUBLIC int DispatchOnLoad(const char *onLoadLabel) { - DispatchHandleT **onloads = configHandle->onloads; - - int err = DispatchOneControl(onloads, onLoadLabel, NULL, NULL_AFBREQ); - return err; -} - -PUBLIC void ctlapi_dispatch(afb_req request) { - DispatchHandleT **controls = configHandle->controls; - json_object *queryJ, *argsJ; - const char *target; - - queryJ = afb_req_json(request); - int err = wrap_json_unpack(queryJ, "{s:s, s:o !}", "target", &target, "args", &argsJ); - if (err) { - afb_req_fail_f(request, "CTL-DISPTACH-INVALID", "missing target or args not a valid json object query=%s", json_object_get_string(queryJ)); - goto OnErrorExit; - } - - (void) DispatchOneControl(controls, target, argsJ, request); - -OnErrorExit: - return; -} - -// Wrapper to Lua2c plugin command add context dans delegate to LuaWrapper -PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback) { -#ifndef CONTROL_SUPPORT_LUA - AFB_ERROR("DISPATCH-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake"); - return 1; -#else - int err=Lua2cWrapper(luaState, funcname, callback, configHandle->plugin->context); - return err; -#endif -} - - -// List Avaliable Configuration Files - -PUBLIC void ctlapi_config(struct afb_req request) { - json_object*tmpJ; - char *dirList; - - json_object* queryJ = afb_req_json(request); - if (queryJ && json_object_object_get_ex(queryJ, "cfgpath", &tmpJ)) { - dirList = strdup(json_object_get_string(tmpJ)); - } else { - dirList = strdup(CONTROL_CONFIG_PATH); - AFB_NOTICE("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH); - } - - // get list of config file - struct json_object *responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, "onload", "json"); - - if (json_object_array_length(responseJ) == 0) { - afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH"); - } else { - afb_req_success(request, responseJ, NULL); - } - - return; -} - -// unpack individual action object - -STATIC int DispatchLoadOneAction(DispatchConfigT *controlConfig, json_object *actionJ, DispatchActionT *action) { - char *api = NULL, *verb = NULL, *callback = NULL, *lua = NULL; - int err, modeCount = 0; - - err = wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s,s?o !}" - , "label", &action->label, "info", &action->info, "callback", &callback, "lua", &lua, "api", &api, "verb", &verb, "args", &action->argsJ); - if (err) { - AFB_ERROR("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ)); - goto OnErrorExit; - } - - if (lua) { - action->mode = CTL_MODE_LUA; - action->call = lua; - modeCount++; - } - - if (api && verb) { - action->mode = CTL_MODE_API; - action->api = api; - action->call = verb; - modeCount++; - } - - if (callback && controlConfig->plugin) { - action->mode = CTL_MODE_CB; - action->call = callback; - modeCount++; - - action->actionCB = dlsym(controlConfig->plugin->dlHandle, callback); - if (!action->actionCB) { - AFB_ERROR("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, controlConfig->plugin->sharelib); - goto OnErrorExit; - } - } - - // make sure at least one mode is selected - if (modeCount == 0) { - AFB_ERROR("DISPATCH-LOAD-ACTION No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); - goto OnErrorExit; - } - - if (modeCount > 1) { - AFB_ERROR("DISPATCH-LOAD-ACTION:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); - goto OnErrorExit; - } - return 0; - -OnErrorExit: - return -1; -}; - -STATIC DispatchActionT *DispatchLoadActions(DispatchConfigT *controlConfig, json_object *actionsJ) { - int err; - DispatchActionT *actions; - - // action array is close with a nullvalue; - if (json_object_get_type(actionsJ) == json_type_array) { - int count = json_object_array_length(actionsJ); - actions = calloc(count + 1, sizeof (DispatchActionT)); - - for (int idx = 0; idx < count; idx++) { - json_object *actionJ = json_object_array_get_idx(actionsJ, idx); - err = DispatchLoadOneAction(controlConfig, actionJ, &actions[idx]); - if (err) goto OnErrorExit; - } - - } else { - actions = calloc(2, sizeof (DispatchActionT)); - err = DispatchLoadOneAction(controlConfig, actionsJ, &actions[0]); - if (err) goto OnErrorExit; - } - - return actions; - -OnErrorExit: - return NULL; - -} - -STATIC DispatchHandleT *DispatchLoadControl(DispatchConfigT *controlConfig, json_object *controlJ) { - json_object *actionsJ, *permissionsJ; - int err; - - DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT)); - err = wrap_json_unpack(controlJ, "{ss,s?s,s?o, so !}", "label", &dispatchHandle->label, "info", &dispatchHandle->info - , "permissions", &permissionsJ, "actions", &actionsJ); - if (err) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ)); - goto OnErrorExit; - } - - dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ); - if (!dispatchHandle->actions) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label); - goto OnErrorExit; - } - return dispatchHandle; - -OnErrorExit: - return NULL; -} - -STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_object *onloadJ) { - json_object *actionsJ = NULL, *requireJ = NULL, *pluginJ = NULL; - int err; - - DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT)); - err = wrap_json_unpack(onloadJ, "{ss,s?s,s?o,s?o,s?o !}", - "label", &dispatchHandle->label, "info", &dispatchHandle->info, "plugin", &pluginJ, "require", &requireJ, "actions", &actionsJ); - if (err) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ)); - goto OnErrorExit; - } - - // best effort to initialise everything before starting - if (requireJ) { - - void DispatchRequireOneApi(json_object * bindindJ) { - const char* requireBinding = json_object_get_string(bindindJ); - err = afb_daemon_require_api(requireBinding, 1); - if (err) { - AFB_WARNING("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding); - } - } - - if (json_object_get_type(requireJ) == json_type_array) { - for (int idx = 0; idx < json_object_array_length(requireJ); idx++) { - DispatchRequireOneApi(json_object_array_get_idx(requireJ, idx)); - } - } else { - DispatchRequireOneApi(requireJ); - } - } - - if (pluginJ) { - json_object *lua2csJ = NULL; - DispatchPluginT *dPlugin= calloc(1, sizeof(DispatchPluginT)); - controlConfig->plugin = dPlugin; - - err = wrap_json_unpack(pluginJ, "{ss,s?s,ss,s?o!}", - "label", &dPlugin->label, "info", &dPlugin->info, "sharelib", &dPlugin->sharelib, "lua2c", &lua2csJ); - if (err) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Plugin missing label|[info]|sharelib|[lua2c] in %s", json_object_get_string(onloadJ)); - goto OnErrorExit; - } - - // search for default policy config file - json_object *pluginPathJ = ScanForConfig(CONTROL_PLUGIN_PATH, CTL_SCAN_RECURSIVE, dPlugin->sharelib, NULL); - if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", dPlugin->sharelib, CONTROL_PLUGIN_PATH); - goto OnErrorExit; - } - - char *filename; - char*fullpath; - err = wrap_json_unpack(json_object_array_get_idx(pluginPathJ, 0), "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); - if (err) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ)); - goto OnErrorExit; - } - - if (json_object_array_length(pluginPathJ) > 1) { - AFB_WARNING("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", fullpath, filename); - } - - char pluginpath[CONTROL_MAXPATH_LEN]; - strncpy(pluginpath, fullpath, sizeof (pluginpath)); - strncat(pluginpath, "/", sizeof (pluginpath)); - strncat(pluginpath, filename, sizeof (pluginpath)); - dPlugin->dlHandle = dlopen(pluginpath, RTLD_NOW); - if (!dPlugin->dlHandle) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror()); - goto OnErrorExit; - } - - CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*) dlsym(dPlugin->dlHandle, "CtlPluginMagic"); - if (!ctlPluginMagic || ctlPluginMagic->magic != CTL_PLUGIN_MAGIC) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath); - goto OnErrorExit; - } else { - AFB_NOTICE("DISPATCH-LOAD-CONFIG:Plugin %s successfully registered", ctlPluginMagic->label); - } - - // Jose hack to make verbosity visible from sharelib - struct afb_binding_data_v2 *afbHidenData = dlsym(dPlugin->dlHandle, "afbBindingV2data"); - if (afbHidenData) *afbHidenData = afbBindingV2data; - - // Push lua2cWrapper @ into plugin - Lua2cWrapperT *lua2cInPlug = dlsym(dPlugin->dlHandle, "Lua2cWrap"); -#ifndef CONTROL_SUPPORT_LUA - if (lua2cInPlug) *lua2cInPlug = NULL; -#else - // Lua2cWrapper is part of binder and not expose to dynamic link - if (lua2cInPlug) *lua2cInPlug = DispatchOneL2c; - - { - int Lua2cAddOne(luaL_Reg *l2cFunc, const char* l2cName, int index) { - char funcName[CONTROL_MAXPATH_LEN]; - strncpy(funcName, "lua2c_", sizeof(funcName)); - strncat(funcName, l2cName, sizeof(funcName)); - - Lua2cFunctionT l2cFunction= (Lua2cFunctionT)dlsym(dPlugin->dlHandle, funcName); - if (!l2cFunction) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'%s' missing err=%s", funcName, dlerror()); - return 1; - } - l2cFunc[index].func=(void*)l2cFunction; - l2cFunc[index].name=strdup(l2cName); - - return 0; - } - - int errCount = 0; - luaL_Reg *l2cFunc=NULL; - int count=0; - - // look on l2c command and push them to LUA - if (json_object_get_type(lua2csJ) == json_type_array) { - int length = json_object_array_length(lua2csJ); - l2cFunc = calloc(length + 1, sizeof (luaL_Reg)); - for (count=0; count < length; count++) { - int err; - const char *l2cName = json_object_get_string(json_object_array_get_idx(lua2csJ, count)); - err = Lua2cAddOne(l2cFunc, l2cName, count); - if (err) errCount++; - } - } else { - l2cFunc = calloc(2, sizeof (luaL_Reg)); - const char *l2cName = json_object_get_string(lua2csJ); - errCount = Lua2cAddOne(l2cFunc, l2cName, 0); - count=1; - } - if (errCount) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin %d symbols not found in plugin='%s'", errCount, pluginpath); - goto OnErrorExit; - } else { - dPlugin->l2cFunc= l2cFunc; - dPlugin->l2cCount= count; - } - } -#endif - DispatchPluginInstallCbT ctlPluginOnload = dlsym(dPlugin->dlHandle, "CtlPluginOnload"); - if (ctlPluginOnload) { - dPlugin->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info); - } - } - - dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ); - if (!dispatchHandle->actions) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchHandle->label); - goto OnErrorExit; - } - return dispatchHandle; - -OnErrorExit: - return NULL; -} - -STATIC DispatchConfigT *DispatchLoadConfig(const char* filepath) { - json_object *controlConfigJ, *ignoreJ; - int err; - - // Load JSON file - controlConfigJ = json_object_from_file(filepath); - if (!controlConfigJ) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath); - goto OnErrorExit; - } - - AFB_INFO("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath); - - json_object *metadataJ = NULL, *onloadsJ = NULL, *controlsJ = NULL, *eventsJ = NULL; - err = wrap_json_unpack(controlConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata", &metadataJ, "onload", &onloadsJ, "controls", &controlsJ, "events", &eventsJ); - if (err) { - AFB_ERROR("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(controlConfigJ)); - goto OnErrorExit; - } - - DispatchConfigT *controlConfig = calloc(1, sizeof (DispatchConfigT)); - if (metadataJ) { - err = wrap_json_unpack(metadataJ, "{ss,s?s,ss !}", "label", &controlConfig->label, "info", &controlConfig->info, "version", &controlConfig->version); - if (err) { - AFB_ERROR("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ)); - goto OnErrorExit; - } - } - - if (onloadsJ) { - DispatchHandleT *dispatchHandle; - - if (json_object_get_type(onloadsJ) != json_type_array) { - controlConfig->onloads = (DispatchHandleT**) calloc(2, sizeof (void*)); - dispatchHandle = DispatchLoadOnload(controlConfig, onloadsJ); - controlConfig->onloads[0] = dispatchHandle; - } else { - int length = json_object_array_length(onloadsJ); - controlConfig->onloads = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); - - for (int jdx = 0; jdx < length; jdx++) { - json_object *onloadJ = json_object_array_get_idx(onloadsJ, jdx); - dispatchHandle = DispatchLoadOnload(controlConfig, onloadJ); - controlConfig->onloads[jdx] = dispatchHandle; - } - } - } - - if (controlsJ) { - DispatchHandleT *dispatchHandle; - - if (json_object_get_type(controlsJ) != json_type_array) { - controlConfig->controls = (DispatchHandleT**) calloc(2, sizeof (void*)); - dispatchHandle = DispatchLoadControl(controlConfig, controlsJ); - controlConfig->controls[0] = dispatchHandle; - } else { - int length = json_object_array_length(controlsJ); - controlConfig->controls = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); - - for (int jdx = 0; jdx < length; jdx++) { - json_object *controlJ = json_object_array_get_idx(controlsJ, jdx); - dispatchHandle = DispatchLoadControl(controlConfig, controlJ); - controlConfig->controls[jdx] = dispatchHandle; - } - } - } - - if (eventsJ) { - DispatchHandleT *dispatchHandle; - - if (json_object_get_type(eventsJ) != json_type_array) { - controlConfig->events = (DispatchHandleT**) calloc(2, sizeof (void*)); - dispatchHandle = DispatchLoadControl(controlConfig, eventsJ); - controlConfig->events[0] = dispatchHandle; - } else { - int length = json_object_array_length(eventsJ); - controlConfig->events = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); - - for (int jdx = 0; jdx < length; jdx++) { - json_object *eventJ = json_object_array_get_idx(eventsJ, jdx); - dispatchHandle = DispatchLoadControl(controlConfig, eventJ); - controlConfig->events[jdx] = dispatchHandle; - } - } - } - - return controlConfig; - -OnErrorExit: - return NULL; -} - - -// Load default config file at init - -PUBLIC int DispatchInit() { - int index, err, luaLoaded = 0; - char controlFile [CONTROL_MAXPATH_LEN]; - - strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN); - strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); - - // search for default dispatch config file - json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH, CTL_SCAN_RECURSIVE, controlFile, "json"); - - // We load 1st file others are just warnings - for (index = 0; index < json_object_array_length(responseJ); index++) { - json_object *entryJ = json_object_array_get_idx(responseJ, index); - - char *filename; - char*fullpath; - err = wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); - if (err) { - AFB_ERROR("DISPATCH-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); - goto OnErrorExit; - } - - if (index == 0) { - if (strcasestr(filename, controlFile)) { - char filepath[CONTROL_MAXPATH_LEN]; - strncpy(filepath, fullpath, sizeof (filepath)); - strncat(filepath, "/", sizeof (filepath)); - strncat(filepath, filename, sizeof (filepath)); - configHandle = DispatchLoadConfig(filepath); - if (!configHandle) { - AFB_ERROR("DISPATCH-INIT:ERROR Fail loading [%s]", filepath); - goto OnErrorExit; - } - luaLoaded = 1; - break; - } - } else { - AFB_WARNING("DISPATCH-INIT:WARNING Secondary Control Config Ignored %s/%s", fullpath, filename); - } - } - - // no dispatch config found remove control API from binder - if (!luaLoaded) { - AFB_WARNING("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile); - } - - AFB_NOTICE("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init"); - return 0; - -OnErrorExit: - AFB_NOTICE("DISPATCH-INIT:ERROR: Audio Control Dispatch Init"); - return 1; -} - - - diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c deleted file mode 100644 index 9d2cceb..0000000 --- a/Controler-afb/ctl-lua.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * 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/ - * https://gist.github.com/SONIC3D/10388137 - */ - -#define _GNU_SOURCE -#include -#include - - -#include "ctl-binding.h" -#include "wrap-json.h" - -#define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg -#define LUA_MSG_MAX_LENGTH 512 -#define JSON_ERROR (json_object*)-1 -static afb_req NULL_AFBREQ = {}; - - -static lua_State* luaState; - -#define CTX_MAGIC 123456789 -#define CTX_TOKEN "AFB_ctx" - -typedef struct { - char *name; - int count; - afb_event event; -} LuaAfbEvent; -static LuaAfbEvent *luaDefaultEvt; - -typedef struct { - int ctxMagic; - afb_req request; - void *handle; - char *info; -} LuaAfbContextT; - -typedef struct { - const char *callback; - json_object *context; - void *handle; -} LuaCallServiceT; - -typedef enum { - AFB_MSG_INFO, - AFB_MSG_WARNING, - AFB_MSG_NOTICE, - AFB_MSG_DEBUG, - AFB_MSG_ERROR, -} LuaAfbMessageT; - -/* - * Note(Fulup): I fail to use luaL_setmetatable and replaced it with a simple opaque - * handle while waiting for someone smarter than me to find a better solution - * https://stackoverflow.com/questions/45596493/lua-using-lua-newuserdata-from-lua-pcall - */ - -STATIC LuaAfbContextT *LuaCtxCheck (lua_State *luaState, int index) { - LuaAfbContextT *afbContext; - //luaL_checktype(luaState, index, LUA_TUSERDATA); - //afbContext = (LuaAfbContextT *)luaL_checkudata(luaState, index, CTX_TOKEN); - luaL_checktype(luaState, index, LUA_TLIGHTUSERDATA); - afbContext = (LuaAfbContextT *) lua_touserdata(luaState, index); - 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, void *handle, const char* info) { - // LuaAfbContextT *afbContext = (LuaAfbContextT *)lua_newuserdata(luaState, sizeof(LuaAfbContextT)); - // luaL_setmetatable(luaState, CTX_TOKEN); - LuaAfbContextT *afbContext = (LuaAfbContextT *)calloc(1, sizeof(LuaAfbContextT)); - lua_pushlightuserdata(luaState, afbContext); - if (!afbContext) { - AFB_ERROR ("LuaCtxPush fail to allocate user data context"); - return NULL; - } - afbContext->ctxMagic=CTX_MAGIC; - afbContext->info=strdup(info); - afbContext->request= request; - afbContext->handle= handle; - return afbContext; -} - -STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { - free(afbContext->info); - free(afbContext); -} - -// Push a json structure on the stack as a LUA table -STATIC int LuaPushArgument (json_object *argsJ) { - - //AFB_NOTICE("LuaPushArgument argsJ=%s", json_object_get_string(argsJ)); - - json_type jtype= json_object_get_type(argsJ); - switch (jtype) { - case json_type_object: { - lua_newtable (luaState); - json_object_object_foreach (argsJ, key, val) { - int done = LuaPushArgument (val); - if (done) { - lua_setfield(luaState,-2, key); - } - } - break; - } - case json_type_array: { - int length= json_object_array_length(argsJ); - lua_newtable (luaState); - for (int idx=0; idx < length; idx ++) { - json_object *val=json_object_array_get_idx(argsJ, idx); - LuaPushArgument (val); - lua_seti (luaState,-2, idx); - } - break; - } - case json_type_int: - lua_pushinteger(luaState, json_object_get_int(argsJ)); - break; - case json_type_string: - lua_pushstring(luaState, json_object_get_string(argsJ)); - break; - case json_type_boolean: - lua_pushboolean(luaState, json_object_get_boolean(argsJ)); - break; - case json_type_double: - lua_pushnumber(luaState, json_object_get_double(argsJ)); - break; - case json_type_null: - AFB_WARNING("LuaPushArgument: NULL object type %s", json_object_get_string(argsJ)); - return 0; - break; - - default: - AFB_ERROR("LuaPushArgument: unsupported Json object type %s", json_object_get_string(argsJ)); - return 0; - } - return 1; -} - -STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx); - -STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { - int idx; - #define LUA_KEY_INDEX -2 - #define LUA_VALUE_INDEX -1 - - json_object *tableJ= json_object_new_object(); - const char *key; - char number[3]; - lua_pushnil(luaState); // 1st key - if (index < 0) index--; // nested table https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c - for (idx=1; lua_next(luaState, index) != 0; idx++) { - - // uses 'key' (at index -2) and 'value' (at index -1) - if (lua_type(luaState,LUA_KEY_INDEX) == LUA_TSTRING) key= lua_tostring(luaState, LUA_KEY_INDEX); - else { - snprintf(number, sizeof(number),"%d", idx); - key=number; - } - json_object *argJ= LuaPopOneArg(luaState, LUA_VALUE_INDEX); - json_object_object_add(tableJ, key, argJ); - lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration - } - - // Query is empty free empty json object - if (idx == 1) { - json_object_put(tableJ); - return NULL; - } - return tableJ; -} - -STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx) { - json_object *value=NULL; - - int luaType = lua_type(luaState, idx); - switch(luaType) { - case LUA_TNUMBER: { - lua_Number number= lua_tonumber(luaState, idx);; - int nombre = (int)number; // evil trick to determine wether n fits in an integer. (stolen from ltcl.c) - if (number == nombre) { - value= json_object_new_int((int)number); - } else { - value= json_object_new_double(number); - } - 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: - value= LuaTableToJson(luaState, idx); - break; - case LUA_TNIL: - value=json_object_new_string("nil") ; - break; - case LUA_TUSERDATA: - value=json_object_new_int64((int64_t)lua_touserdata(luaState, idx)); // store userdata as int !!! - break; - - default: - AFB_NOTICE ("LuaPopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); - value=NULL; - } - - return value; -} - -static json_object *LuaPopArgs (lua_State* luaState, int start) { - json_object *responseJ; - - int stop = lua_gettop(luaState); - if(stop-start <0) return NULL; - - // start at 2 because we are using a function array lib - if (start == stop) { - responseJ=LuaPopOneArg (luaState, start); - } else { - // loop on remaining return arguments - responseJ= json_object_new_array(); - for (int idx=start; idx <= stop; idx++) { - json_object *argJ=LuaPopOneArg (luaState, idx); - if (!argJ) goto OnErrorExit; - json_object_array_add(responseJ, argJ); - } - } - - return responseJ; - - OnErrorExit: - return NULL; -} - - -STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { - char *message; - - json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG); - - if (!responseJ) { - luaL_error(luaState,"LuaFormatMessage empty message"); - goto OnErrorExit; - } - - // if we have only on argument just return the value. - if (json_object_get_type(responseJ)!=json_type_array || json_object_array_length(responseJ) <2) { - message= (char*)json_object_get_string(responseJ); - goto PrintMessage; - } - - // extract format and push all other parameter on the stack - message = alloca (LUA_MSG_MAX_LENGTH); - const char *format = json_object_get_string(json_object_array_get_idx(responseJ, 0)); - - int arrayIdx=1; - int targetIdx=0; - - for (int idx=0; format[idx] !='\0'; idx++) { - - if (format[idx]=='%' && format[idx] !='\0') { - json_object *slotJ= json_object_array_get_idx(responseJ, arrayIdx); - //if (slotJ) AFB_NOTICE("**** idx=%d slotJ=%s", arrayIdx, json_object_get_string(slotJ)); - - - switch (format[++idx]) { - case 'd': - if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%d", json_object_get_int(slotJ)); - else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); - arrayIdx++; - break; - case 'f': - if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%f", json_object_get_double(slotJ)); - else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); - arrayIdx++; - break; - - case'%': - message[targetIdx]='%'; - targetIdx++; - break; - - case 's': - default: - if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%s", json_object_get_string(slotJ)); - else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); - arrayIdx++; - } - - } else { - if (targetIdx >= LUA_MSG_MAX_LENGTH) { - AFB_WARNING ("LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH); - targetIdx --; // move backward for EOL - break; - } else { - message[targetIdx++] = format[idx]; - } - } - } - message[targetIdx]='\0'; - -PrintMessage: - switch (action) { - case AFB_MSG_WARNING: - AFB_WARNING (message); - break; - case AFB_MSG_NOTICE: - AFB_NOTICE (message); - break; - case AFB_MSG_DEBUG: - AFB_DEBUG (message); - break; - case AFB_MSG_INFO: - AFB_INFO (message); - break; - case AFB_MSG_ERROR: - default: - AFB_ERROR (message); - } - return 0; // nothing return to lua - - OnErrorExit: // on argument to return (the error message) - return 1; -} - -STATIC int LuaPrintInfo(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_INFO); - return err; -} - -STATIC int LuaPrintError(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_ERROR); - return err; // no value return -} - -STATIC int LuaPrintWarning(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_WARNING); - return err; -} - -STATIC int LuaPrintNotice(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_NOTICE); - return err; -} - -STATIC int LuaPrintDebug(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG); - return err; -} - -STATIC int LuaAfbSuccess(lua_State* luaState) { - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; - - // ignore context argument - json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); - if (responseJ == JSON_ERROR) return 1; - - afb_req_success(afbContext->request, responseJ, NULL); - - LuaCtxFree(afbContext); - return 0; - - OnErrorExit: - lua_error(luaState); - return 1; -} - -STATIC int LuaAfbFail(lua_State* luaState) { - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; - - json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); - if (responseJ == JSON_ERROR) return 1; - - afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(responseJ)); - - 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; - int count=1; - - lua_getglobal(luaState, contextCB->callback); - - // push error status & response - lua_pushboolean(luaState, iserror); - count+= LuaPushArgument(responseJ); - count+= LuaPushArgument(contextCB->context); - - int err=lua_pcall(luaState, count, LUA_MULTRET, 0); - if (err) { - AFB_ERROR ("LUA-SERICE-CB:FAIL response=%s err=%s", json_object_get_string(responseJ), lua_tostring(luaState,-1) ); - } - - free (contextCB); -} - - -STATIC int LuaAfbService(lua_State* luaState) { - int count = lua_gettop(luaState); - - // note: argument start at 2 because of AFB: table - 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; - } - - // get api/verb+query - const char *api = lua_tostring(luaState,2); - const char *verb= lua_tostring(luaState,3); - json_object *queryJ= LuaTableToJson(luaState, 4); - if (queryJ == JSON_ERROR) return 1; - - LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); - contextCB->callback= lua_tostring(luaState, 5); - contextCB->context = LuaPopArgs(luaState, 6); - - afb_service_call(api, verb, queryJ, LuaAfbServiceCB, contextCB); - - return 0; // no value return - - OnErrorExit: - lua_error(luaState); - return 1; -} - -STATIC int LuaAfbServiceSync(lua_State* luaState) { - int count = lua_gettop(luaState); - json_object *responseJ; - - // note: argument start at 2 because of AFB: table - if (count <3 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4)) { - lua_pushliteral (luaState, "LuaAfbServiceSync-Syntax is error,data=AFB:service_call (api, verb, query)"); - goto OnErrorExit; - } - - // get api/verb+query - const char *api = lua_tostring(luaState,2); - const char *verb= lua_tostring(luaState,3); - json_object *queryJ= LuaTableToJson(luaState, 4); - - int iserror=afb_service_call_sync (api, verb, queryJ, &responseJ); - - // push error status & response - count=1; lua_pushboolean(luaState, iserror); - count+= LuaPushArgument(responseJ); - - return count; // return count values - - OnErrorExit: - lua_error(luaState); - return 1; -} - -STATIC int LuaAfbEventPush(lua_State* luaState) { - LuaAfbEvent *afbevt; - int index; - - // if no private event handle then use default binding event - if (lua_islightuserdata(luaState, LUA_FIST_ARG)) { - afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG); - index=LUA_FIST_ARG+1; - } else { - index=LUA_FIST_ARG; - afbevt=luaDefaultEvt; - } - - if (!afb_event_is_valid(afbevt->event)) { - lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event"); - goto OnErrorExit; - } - - json_object *ctlEventJ= LuaTableToJson(luaState, index); - if (!ctlEventJ) { - lua_pushliteral (luaState, "LuaAfbEventPush-Syntax is AFB:signal ([evtHandle], {lua table})"); - goto OnErrorExit; - } - - int done = afb_event_push(afbevt->event, ctlEventJ); - if (!done) { - lua_pushliteral (luaState, "LuaAfbEventPush-Fail No Subscriber to event"); - AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); - goto OnErrorExit; - } - afbevt->count++; - return 0; - - OnErrorExit: - lua_error(luaState); - return 1; -} - -STATIC int LuaAfbEventSubscribe(lua_State* luaState) { - LuaAfbEvent *afbevt; - - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) { - lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail Invalid request handle"); - goto OnErrorExit; - } - - // if no private event handle then use default binding event - if (lua_islightuserdata(luaState, LUA_FIST_ARG+1)) { - afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG+1); - } else { - afbevt=luaDefaultEvt; - } - - if (!afb_event_is_valid(afbevt->event)) { - lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event handle"); - goto OnErrorExit; - } - - int err = afb_req_subscribe(afbContext->request, afbevt->event); - if (err) { - lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail No Subscriber to event"); - AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); - goto OnErrorExit; - } - afbevt->count++; - return 0; - - OnErrorExit: - lua_error(luaState); - return 1; -} - -STATIC int LuaAfbEventMake(lua_State* luaState) { - int count = lua_gettop(luaState); - LuaAfbEvent *afbevt=calloc(1,sizeof(LuaAfbEvent)); - - if (count != LUA_FIST_ARG || !lua_isstring(luaState, LUA_FIST_ARG)) { - lua_pushliteral (luaState, "LuaAfbEventMake-Syntax is evtHandle= AFB:event ('myEventName')"); - goto OnErrorExit; - } - - // event name should be the only argument - afbevt->name= strdup (lua_tostring(luaState,LUA_FIST_ARG)); - - // create a new binder event - afbevt->event = afb_daemon_make_event(afbevt->name); - if (!afb_event_is_valid(afbevt->event)) { - lua_pushliteral (luaState, "LuaAfbEventMake-Fail to Create Binder event"); - goto OnErrorExit; - } - - // push event handler as a LUA opaque handle - lua_pushlightuserdata(luaState, afbevt); - return 1; - - OnErrorExit: - lua_error(luaState); - return 1; -} - -// Function call from LUA when lua2c plugin L2C is used -PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context) { - - json_object *argsJ= LuaPopArgs(luaState, LUA_FIST_ARG); - int response = (*callback) (funcname, argsJ, context); - - // push response to LUA - lua_pushinteger(luaState, response); - return 1; -} - -// Generated some fake event based on watchdog/counter -PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ) { - - int err, count; - - json_object* argsJ = action->argsJ; - const char* func = action->call; - - // load function (should exist in CONTROL_PATH_LUA - lua_getglobal(luaState, func); - - // push argsJ on the stack - count=0; - if (!argsJ) { - lua_pushnil(luaState); - count++; - } else { - count+= LuaPushArgument (argsJ); - } - - // push queryJ on the stack - if (!queryJ) { - lua_pushnil(luaState); - count++; - } else { - count+= LuaPushArgument (queryJ); - } - - // effectively exec LUA script code - err=lua_pcall(luaState, count, 1, 0); - if (err) { - AFB_ERROR("LuaCallFunc Fail calling %s error=%s", func, lua_tostring(luaState,-1)); - goto OnErrorExit; - } - - // return LUA script value - int rc= (int)lua_tointeger(luaState, -1); - return rc; - - OnErrorExit: - return -1; -} - - -// Execute LUA code from received API request -STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { - - int err, count=0; - - json_object* queryJ = afb_req_json(request); - - switch (action) { - - case LUA_DOSTRING: { - const char *script = json_object_get_string(queryJ); - err=luaL_loadstring(luaState, script); - if (err) { - 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,NULL,script); - if (!afbContext) goto OnErrorExit; - - break; - } - - case LUA_DOCALL: { - const char *func; - json_object *argsJ=NULL; - - err= wrap_json_unpack (queryJ, "{s:s, s?o !}", "func", &func, "args", &argsJ); - if (err) { - AFB_ERROR ("LUA-DOCALL-SYNTAX missing func|args query=%s", json_object_get_string(queryJ)); - goto OnErrorExit; - } - - // load function (should exist in CONTROL_PATH_LUA - lua_getglobal(luaState, func); - - // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); - if (!afbContext) goto OnErrorExit; - - // push query on the stack - if (!argsJ) { - lua_pushnil(luaState); - count++; - } else { - count+= LuaPushArgument (argsJ); - } - - break; - } - - case LUA_DOSCRIPT: { // Fulup need to fix argument passing - const char *script; - char*func=NULL; - char *filename; char*fullpath; - char luaScriptPath[CONTROL_MAXPATH_LEN]; - json_object *argsJ=NULL; - int index; - - // scan luascript search path once - static json_object *luaScriptPathJ =NULL; - - err= wrap_json_unpack (queryJ, "{s:s, s?s s?o !}", "script", &script,"func", &func, "args", &argsJ); - if (err) { - AFB_ERROR ("LUA-DOSCRIPT-SYNTAX:missing script|(args,arg) query=%s", json_object_get_string(queryJ)); - goto OnErrorExit; - } - - // search for filename=script in CONTROL_LUA_PATH - if (!luaScriptPathJ) luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE,CONTROL_DOSCRIPT_PRE "-", script); - for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { - json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); - - err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); - if (err) { - AFB_ERROR ("LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ)); - goto OnErrorExit; - } - - if (index > 0) AFB_WARNING("LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); - else { - strncpy (luaScriptPath, fullpath, sizeof(luaScriptPath)); - strncat (luaScriptPath, "/", sizeof(luaScriptPath)); - strncat (luaScriptPath, filename, sizeof(luaScriptPath)); - } - } - - err= luaL_loadfile(luaState, luaScriptPath); - if (err) { - AFB_ERROR ("LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); - goto OnErrorExit; - } - - // script was loaded we need to parse to make it executable - err=lua_pcall(luaState, 0, 0, 0); - if (err) { - AFB_ERROR ("LUA-DOSCRIPT:FAIL to load %s", luaScriptPath); - goto OnErrorExit; - } - - // if no func name given try to deduct from filename - if (!func) func= (char*)GetMidleName(filename); - if (!func) { - AFB_ERROR ("LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); - goto OnErrorExit; - } - - // load function (should exist in CONTROL_PATH_LUA - lua_getglobal(luaState, func); - - // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); - if (!afbContext) goto OnErrorExit; - - // push function arguments - if (!argsJ) { - lua_pushnil(luaState); - count++; - } else { - count+= LuaPushArgument(argsJ); - } - - break; - } - - default: - AFB_ERROR ("LUA-DOSCRIPT-ACTION unknown query=%s", json_object_get_string(queryJ)); - goto OnErrorExit; - } - - // effectively exec LUA code (afb_reply/fail done later from callback) - err=lua_pcall(luaState, count+1, 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; - } - return; - - OnErrorExit: - afb_req_fail(request,"LUA:ERROR", lua_tostring(luaState,-1)); - return; -} - -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 int LuaTimerClear (lua_State* luaState) { - - // Get Timer Handle - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; - - // retrieve useful information opaque handle - TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; - - AFB_NOTICE ("LuaTimerClear timer=%s", timerHandle->label); - TimerEvtStop(timerHandle); - - return 0; //happy end - -OnErrorExit: - return 1; -} -STATIC int LuaTimerGet (lua_State* luaState) { - - // Get Timer Handle - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; - - // retrieve useful information opaque handle - TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; - - // create response as a JSON object - json_object *responseJ= json_object_new_object(); - json_object_object_add(responseJ,"label", json_object_new_string(timerHandle->label)); - json_object_object_add(responseJ,"delay", json_object_new_int(timerHandle->delay)); - json_object_object_add(responseJ,"count", json_object_new_int(timerHandle->count)); - - // return JSON object as Lua table - int count=LuaPushArgument(responseJ); - - // free json object - json_object_put(responseJ); - - return count; // return argument - -OnErrorExit: - return 0; -} - -// Timer Callback - -// Set timer -STATIC int LuaTimerSetCB (void *handle) { - LuaCallServiceT *contextCB =(LuaCallServiceT*) handle; - TimerHandleT *timerHandle = (TimerHandleT*) contextCB->handle; - int count; - - // push timer handle and user context on Lua stack - lua_getglobal(luaState, contextCB->callback); - - // Push timer handle - LuaAfbContextT *afbContext= LuaCtxPush(luaState, NULL_AFBREQ, contextCB->handle, timerHandle->label); - if (!afbContext) goto OnErrorExit; - count=1; - - // Push user Context - count+= LuaPushArgument(contextCB->context); - - int err=lua_pcall(luaState, count, LUA_MULTRET, 0); - if (err) { - AFB_ERROR ("LUA-TIMER-CB:FAIL response=%s err=%s", json_object_get_string(contextCB->context), lua_tostring(luaState,-1)); - goto OnErrorExit; - } - - // get return parameter - if (!lua_isboolean(luaState, -1)) { - return (lua_toboolean(luaState, -1)); - } - - // timer last run free context resource - if (timerHandle->count == 1) { - LuaCtxFree(afbContext); - } - return 0; // By default we are happy - - OnErrorExit: - return 1; // stop timer -} - -STATIC int LuaTimerSet(lua_State* luaState) { - const char *label=NULL, *info=NULL; - int delay=0, count=0; - - json_object *timerJ = LuaPopOneArg(luaState, LUA_FIST_ARG); - const char *callback = lua_tostring(luaState, LUA_FIST_ARG + 1); - json_object *contextJ = LuaPopOneArg(luaState, LUA_FIST_ARG + 2); - - if (lua_gettop(luaState) != LUA_FIST_ARG+2 || !timerJ || !callback || !contextJ) { - lua_pushliteral(luaState, "LuaTimerSet-Syntax timerset (timerT, 'callback', contextT)"); - goto OnErrorExit; - } - - int err = wrap_json_unpack(timerJ, "{ss, s?s si, si !}", "label", &label, "info", &info, "delay", &delay, "count", &count); - if (err) { - lua_pushliteral(luaState, "LuaTimerSet-Syntax timerT={label:xxx delay:ms, count:xx}"); - goto OnErrorExit; - } - - // everything look fine create timer structure - TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); - timerHandle->delay=delay; - timerHandle->count=count; - timerHandle->label=label; - - // Allocate handle to store context and callback - LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); - contextCB->callback= callback; - contextCB->context = contextJ; - contextCB->handle = timerHandle; - - // fire timer - TimerEvtStart (timerHandle, LuaTimerSetCB, contextCB); - - return 0; // Happy No Return Function - -OnErrorExit: - lua_error(luaState); - return 1; // return error code -} - -// Register a new L2c list of LUA user plugin commands -PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count) { - // luaL_newlib(luaState, l2cFunc); macro does not work with pointer :( - luaL_checkversion(luaState); - lua_createtable(luaState, 0, count+1); - luaL_setfuncs(luaState,l2cFunc,0); - lua_setglobal(luaState, label); -} - -static const luaL_Reg afbFunction[] = { - {"timerclear", LuaTimerClear}, - {"timerget" , LuaTimerGet}, - {"timerset" , LuaTimerSet}, - {"notice" , LuaPrintNotice}, - {"info" , LuaPrintInfo}, - {"warning" , LuaPrintWarning}, - {"debug" , LuaPrintDebug}, - {"error" , LuaPrintError}, - {"callsync" , LuaAfbServiceSync}, - {"service" , LuaAfbService}, - {"success" , LuaAfbSuccess}, - {"fail" , LuaAfbFail}, - {"subscribe" , LuaAfbEventSubscribe}, - {"evtmake" , LuaAfbEventMake}, - {"evtpush" , LuaAfbEventPush}, - - {NULL, NULL} /* sentinel */ -}; - -// Create Binding Event at Init -PUBLIC int LuaLibInit () { - int err, index; - - // search for default policy config file - char fullprefix[CONTROL_MAXPATH_LEN]; - strncpy (fullprefix, CONTROL_CONFIG_PRE "-", sizeof(fullprefix)); - strncat (fullprefix, GetBinderName(), sizeof(fullprefix)); - strncat (fullprefix, "-", sizeof(fullprefix)); - - json_object *luaScriptPathJ = ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, fullprefix, "lua"); - - // open a new LUA interpretor - luaState = luaL_newstate(); - if (!luaState) { - AFB_ERROR ("LUA_INIT: Fail to open lua interpretor"); - goto OnErrorExit; - } - - // load auxiliary libraries - luaL_openlibs(luaState); - - // redirect print to AFB_NOTICE - luaL_newlib(luaState, afbFunction); - lua_setglobal(luaState, "AFB"); - - // create default lua event to send test pause/resume - luaDefaultEvt=calloc(1,sizeof(LuaAfbEvent)); - luaDefaultEvt->name=CONTROL_LUA_EVENT; - luaDefaultEvt->event = afb_daemon_make_event(CONTROL_LUA_EVENT); - if (!afb_event_is_valid(luaDefaultEvt->event)) { - AFB_ERROR ("POLCTL_INIT: Cannot register lua-events=%s ", CONTROL_LUA_EVENT); - goto OnErrorExit;; - } - - // load+exec any file found in LUA search path - for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { - json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); - - char *filename; char*fullpath; - err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); - if (err) { - AFB_ERROR ("LUA-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ)); - goto OnErrorExit; - } - - char filepath[CONTROL_MAXPATH_LEN]; - strncpy(filepath, fullpath, sizeof(filepath)); - strncat(filepath, "/", sizeof(filepath)); - strncat(filepath, filename, sizeof(filepath)); - err= luaL_loadfile(luaState, filepath); - if (err) { - AFB_ERROR ("LUA-LOAD HOOPs Error in LUA loading scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); - goto OnErrorExit; - } - - // exec/compil script - err = lua_pcall(luaState, 0, 0, 0); - if (err) { - AFB_ERROR ("LUA-LOAD HOOPs Error in LUA exec scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); - goto OnErrorExit; - } - } - - // no policy config found remove control API from binder - if (index == 0) { - AFB_WARNING ("POLICY-INIT:WARNING No Control LUA file in path=[%s]", CONTROL_LUA_PATH); - } - - AFB_DEBUG ("Audio control-LUA Init Done"); - return 0; - - OnErrorExit: - return 1; -} - \ No newline at end of file diff --git a/Controler-afb/ctl-plugin-sample.c b/Controler-afb/ctl-plugin-sample.c deleted file mode 100644 index 1d24487..0000000 --- a/Controler-afb/ctl-plugin-sample.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Sample plugin for Controller - */ - - -#define _GNU_SOURCE -#include -#include - -#include "ctl-binding.h" - -#define MY_PLUGIN_MAGIC 987654321 - -typedef struct { - int magic; - int count; -} MyPluginCtxT; - -STATIC const char* jsonToString (json_object *valueJ) { - const char *value; - if (valueJ) - value=json_object_get_string(valueJ); - else - value="NULL"; - - return value; -} - -// Declare this sharelib as a Controller Plugin -CTLP_REGISTER("MyCtlSamplePlugin"); - -// Call at initialisation time -PUBLIC CTLP_ONLOAD(label, version, info) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)calloc (1, sizeof(MyPluginCtxT)); - pluginCtx->magic = MY_PLUGIN_MAGIC; - pluginCtx->count = -1; - - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Onload label=%s version=%s info=%s", label, info, version); - return (void*)pluginCtx; -} - -PUBLIC CTLP_CAPI (SamplePolicyInit, label, argsJ, queryJ, context) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; - if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { - AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:SamplePolicyInit (Hoops) Invalid Sample Plugin Context"); - return -1; - }; - - pluginCtx->count = 0; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Init label=%s args=%s\n", label, jsonToString(argsJ)); - return 0; -} - -PUBLIC CTLP_CAPI (sampleControlMultimedia,label, argsJ,queryJ,context) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; - - if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { - AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia (Hoops) Invalid Sample Plugin Context"); - return -1; - }; - pluginCtx->count++; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d" - , label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); - return 0; -} - -PUBLIC CTLP_CAPI (sampleControlNavigation, label, argsJ, queryJ, context) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; - - if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { - AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:sampleControlNavigation (Hoops) Invalid Sample Plugin Context"); - return -1; - }; - pluginCtx->count++; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlNavigation SamplePolicyCount action=%s args=%s query=%s count=%d" - ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); - return 0; -} - -PUBLIC CTLP_CAPI (SampleControlEvent, label, argsJ, queryJ, context) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; - - if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { - AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:cousampleControlMultimediant (Hoops) Invalid Sample Plugin Context"); - return -1; - }; - pluginCtx->count++; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d" - ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); - return 0; -} - -// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file -PUBLIC CTLP_LUA2C (Lua2cHelloWorld1, label, argsJ, context) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; - - if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { - AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 (Hoops) Invalid Sample Plugin Context"); - return -1; - }; - pluginCtx->count++; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 SamplePolicyCount action=%s args=%s count=%d" - ,label, jsonToString(argsJ), pluginCtx->count); - return 0; -} - -// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file -PUBLIC CTLP_LUA2C (Lua2cHelloWorld2, label, argsJ, context) { - MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; - - if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { - AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 (Hoops) Invalid Sample Plugin Context"); - return -1; - }; - pluginCtx->count++; - AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 SamplePolicyCount action=%s args=%s count=%d" - ,label, jsonToString(argsJ), pluginCtx->count); - return 0; -} diff --git a/Controler-afb/ctl-policy.c b/Controler-afb/ctl-policy.c deleted file mode 100644 index e9798b3..0000000 --- a/Controler-afb/ctl-policy.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, something express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "wrap-json.h" -#include "ctl-binding.h" - -STATIC PolicyCtlConfigT *ctlHandle = NULL; - -// List Avaliable Configuration Files -STATIC json_object* ScanForConfig (char* searchPath) { - json_object *responseJ; - DIR *dirHandle; - char *dirPath; - char* dirList= strdup(searchPath); - - responseJ = json_object_new_array(); - for (dirPath= strtok(dirList, ":"); dirPath && *dirPath; dirPath=strtok(NULL,":")) { - struct dirent *dirEnt; - - dirHandle = opendir (dirPath); - if (!dirHandle) { - AFB_NOTICE ("CONFIG-SCANNING dir=%s not readable", dirPath); - continue; - } - - AFB_NOTICE ("CONFIG-SCANNING:ctl_listconfig scanning: %s", dirPath); - while ((dirEnt = readdir(dirHandle)) != NULL) { - // Unknown type is accepted to support dump filesystems - if (dirEnt->d_type == DT_REG || dirEnt->d_type == DT_UNKNOWN) { - struct json_object *pathJ = json_object_new_object(); - json_object_object_add(pathJ, "dirpath", json_object_new_string(dirPath)); - json_object_object_add(pathJ, "filename", json_object_new_string(dirEnt->d_name)); - json_object_array_add(responseJ, pathJ); - } - } - } - - free (dirList); - return (responseJ); -} - -PUBLIC void ctlapi_authorize (PolicyCtlEnumT control, afb_req request) { - json_object*tmpJ; - - json_object* queryJ= afb_req_json(request); - int done=json_object_object_get_ex(queryJ, "closing", &tmpJ); - if (done) return; - -} - - -// List Avaliable Configuration Files -PUBLIC void ctlapi_config (struct afb_req request) { - json_object*tmpJ; - char *dirList; - - json_object* queryJ = afb_req_json(request); - if (queryJ && json_object_object_get_ex (queryJ, "cfgpath" , &tmpJ)) { - dirList = strdup (json_object_get_string(tmpJ)); - } else { - dirList = strdup (CONTROL_CONFIG_PATH); - AFB_NOTICE ("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH); - } - - // get list of config file - struct json_object *responseJ = ScanForConfig(dirList); - - if (json_object_array_length(responseJ) == 0) { - afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH"); - } else { - afb_req_success(request, responseJ, NULL); - } - - return; -} - -STATIC PolicyActionT **PolicyLoadActions (json_object *actionsJ) { - int err; - PolicyActionT ** actions; - - // unpack individual action object - int actionUnpack (json_object *actionJ, PolicyActionT *action) { - - err= wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s !}" - , "label",&action->label, "info",&action->info, "callback",&action->callback, "query",&queryJ, "api",&action->api, "verb", &action->verb); - if (err) { - AFB_ERROR ("POLICY-LOAD-ACTION Missing something label|info|callback|api|verb|query in %s", json_object_get_string(actionJ)); - return -1; - } - if (!action->callback || !(action->api && action->verb)) { - AFB_ERROR ("POLICY-LOAD-ACTION Missing something callback|(api+verb) in %s", json_object_get_string(actionJ)); - return -1; - } - return 0; - }; - - // action array is close with a nullvalue; - if (json_object_get_type(actionsJ) == json_type_array) { - int count = json_object_array_length(actionsJ); - actions = calloc (count+1, sizeof(PolicyActionT)); - - for (int idx=0; idx < count; idx++) { - json_object *actionJ = json_object_array_get_idx(actionsJ, idx); - err = actionUnpack (actionJ, &actions[idx]); - if (err) goto OnErrorExit; - } - - } else { - actions = calloc (2, sizeof(PolicyActionT)); - err = actionUnpack (actionsJ, &actions[0]); - if (err) goto OnErrorExit; - } - - return actions; - - OnErrorExit: - return NULL; - -} - -// load control policy from file using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values -STATIC PolicyCtlConfigT *PolicyLoadConfig (const char* filepath) { - json_object *policyConfigJ, *ignoreJ, *actionsJ; - PolicyCtlConfigT *policyConfig = calloc (1, sizeof(PolicyCtlConfigT)); - int err; - - // Load JSON file - policyConfigJ= json_object_from_file(filepath); - if (!policyConfigJ) goto OnErrorExit; - - json_object *metadataJ, *onloadJ, *controlsJ, *eventsJ; - err= wrap_json_unpack(policyConfigJ, "{s?o,so,s?o,so,so !}", "$schema", &ignoreJ, "metadata",&metadataJ, "onload",&onloadJ, "controls",&controlsJ, "events",&eventsJ); - if (err) { - AFB_ERROR ("POLICY-LOAD-ERRROR Missing something metadata|onload|controls|events in %s", json_object_get_string(policyConfigJ)); - goto OnErrorExit; - } - - PolicyHandleT *policyHandle = calloc (1, sizeof(PolicyHandleT)); - err= wrap_json_unpack(metadataJ, "{so,s?s,s?s !}", "label", &policyHandle->label, "info",&policyHandle->info, "version",&policyHandle->version); - if (err) { - AFB_ERROR ("POLICY-LOAD-CONFIG Missing something label|info|version in %s", json_object_get_string(metadataJ)); - goto OnErrorExit; - } - - if (onloadJ) { - err= wrap_json_unpack(onloadJ, "{s?o,s?s,s?s !}", "info",&ignoreJ, "label",&ignoreJ, "actions",&actionsJ); - if (err) { - AFB_ERROR ("POLICY-LOAD-CONFIG Missing something label|info|plugin|actions in %s", json_object_get_string(metadataJ)); - goto OnErrorExit; - } - policyConfig->onload = PolicyLoadActions (actionsJ); - } - - return policyControl; - -OnErrorExit: - return NULL; -} - -// Load default config file at init -PUBLIC int PolicyInit () { - int index, err; - - - // search for default policy config file - json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH); - - for (index=0; index < json_object_array_length(responseJ); index++) { - json_object *entryJ=json_object_array_get_idx(responseJ, index); - - char *filename; char*dirpath; - err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "dirpath", &dirpath,"filename", &filename); - if (err) { - AFB_ERROR ("POLICY-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ)); - goto OnErrorExit; - } - - if (strcasestr(filename, CONTROL_CONFIG_FILE)) { - char filepath[255]; - strncpy(filepath, dirpath, sizeof(filepath)); - strncat(filepath, "/", sizeof(filepath)); - strncat(filepath, filename, sizeof(filepath)); - ctlHandle = PolicyLoadConfig (filepath); - if (!ctlHandle) goto OnErrorExit; - break; - } - } - - // no policy config found remove control API from binder - if (index == 0) goto OnErrorExit; - - AFB_NOTICE ("SUCCES: Audio Control Policy Init"); - return 0; - -OnErrorExit: - AFB_NOTICE ("ERROR: Audio Control Policy Init"); - return 1; -} - - - diff --git a/Controler-afb/ctl-timer.c b/Controler-afb/ctl-timer.c deleted file mode 100644 index f7ee6f0..0000000 --- a/Controler-afb/ctl-timer.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "ctl-binding.h" - -#define DEFAULT_PAUSE_DELAY 3000 -#define DEFAULT_TEST_COUNT 1 -typedef struct { - int value; - const char *label; -} AutoTestCtxT; - -static afb_event afbevt; - -STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { - TimerHandleT *timerHandle = (TimerHandleT*) handle; - int done; - uint64_t usec; - - // Rearm timer if needed - timerHandle->count --; - if (timerHandle->count == 0) { - sd_event_source_unref(source); - free (handle); - return 0; - } - else { - // otherwise validate timer for a new run - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); - sd_event_source_set_time(source, usec + timerHandle->delay*1000); - } - - done= timerHandle->callback(timerHandle->context); - if (!done) goto OnErrorExit; - - return 0; - -OnErrorExit: - AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->label); - return -1; -} - -PUBLIC void TimerEvtStop(TimerHandleT *timerHandle) { - - sd_event_source_unref(timerHandle->evtSource); - free (timerHandle); -} - - -PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context) { - uint64_t usec; - - // populate CB handle - timerHandle->callback=callback; - timerHandle->context=context; - - // set a timer with ~250us accuracy - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay*1000, 250, TimerNext, timerHandle); -} - -PUBLIC afb_event TimerEvtGet(void) { - return afbevt; -} - - -STATIC int DoSendEvent (void *context) { - AutoTestCtxT *ctx= (AutoTestCtxT*)context; - json_object *ctlEventJ; - - if (ctx->value) ctx->value =0; - else ctx->value =1; - - ctlEventJ = json_object_new_object(); - json_object_object_add(ctlEventJ,"signal", json_object_new_string(ctx->label)); - json_object_object_add(ctlEventJ,"value" , json_object_new_int(ctx->value)); - int done = afb_event_push(afbevt, ctlEventJ); - - AFB_NOTICE ("DoSendEvent {action: '%s', value:%d} status=%d", ctx->label, ctx->value, done); - - return (done); -} - -// Generated some fake event based on watchdog/counter -PUBLIC void ctlapi_timer_test (afb_req request) { - json_object *queryJ, *tmpJ; - TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); - AutoTestCtxT *context = calloc (1, sizeof (AutoTestCtxT)); - int done; - - queryJ= afb_req_json(request); - - // Closing call only has one parameter - done=json_object_object_get_ex(queryJ, "closing", &tmpJ); - if (done) return; - - done=json_object_object_get_ex(queryJ, "label", &tmpJ); - if (!done) { - afb_req_fail_f(request, "TEST-LABEL-MISSING", "label is mandatory for event_test"); - goto OnErrorExit; - } - timerHandle->label = strdup(json_object_get_string (tmpJ)); - - json_object_object_get_ex(queryJ, "delay", &tmpJ); - timerHandle->delay = json_object_get_int (tmpJ) * 1000; - if (timerHandle->delay == 0) timerHandle->delay=DEFAULT_PAUSE_DELAY * 1000; - - json_object_object_get_ex(queryJ, "count", &tmpJ); - timerHandle->count = json_object_get_int (tmpJ); - if (timerHandle->count == 0) timerHandle->count=DEFAULT_TEST_COUNT; - - // start a lool timer - TimerEvtStart (timerHandle, DoSendEvent, context); - - afb_req_success(request, NULL, NULL); - return; - - OnErrorExit: - return; -} - -// Create Binding Event at Init -PUBLIC int TimerEvtInit () { - - // create binder event to send test pause/resume - afbevt = afb_daemon_make_event("control"); - if (!afb_event_is_valid(afbevt)) { - AFB_ERROR ("POLCTL_INIT: Cannot register ctl-events"); - return 1; - } - - AFB_DEBUG ("Audio Control-Events Init Done"); - return 0; -} - diff --git a/Controller-afb/CMakeLists.txt b/Controller-afb/CMakeLists.txt new file mode 100644 index 0000000..a9e8e60 --- /dev/null +++ b/Controller-afb/CMakeLists.txt @@ -0,0 +1,84 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################### + + +# Generate API-v2 hat from OpenAPI json definition +macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME) + add_custom_command(OUTPUT ${API_DEF_NAME}.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${API_DEF_NAME}.json + COMMAND afb-genskel ${API_DEF_NAME}.json >${API_DEF_NAME}.h + ) + add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h) + add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI) +endmacro(SET_TARGET_GENSKEL) + +# Include LUA only when requested +if(CONTROL_SUPPORT_LUA) + message(STATUS "Notice: LUA Controler Support Selected") + set(CTL_LUA_SOURCE ctl-lua.c) +endif(CONTROL_SUPPORT_LUA) + +# Add target to project dependency list +PROJECT_TARGET_ADD(control-afb) + + # Define project Targets + ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-timer.c ctl-dispatch.c ${CTL_LUA_SOURCE}) + + # Generate API-v2 hat from OpenAPI json definition + SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "afb-" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + audio-common + ${link_libraries} + ) + + # installation directory + INSTALL(TARGETS ${TARGET_NAME} + LIBRARY DESTINATION CMAKE_INSTALL_PREFIX ) + +PROJECT_TARGET_ADD(audio-plugin-sample) + + # Define targets + ADD_LIBRARY(${TARGET_NAME} MODULE ctl-plugin-sample.c) + + # Alsa Plugin properties + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX ${CTL_PLUGIN_PRE} + SUFFIX ${CTL_PLUGIN_EXT} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + audio-common + ${link_libraries} + ) + + # installation directory + INSTALL(TARGETS ${TARGET_NAME} + LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}/controler) diff --git a/Controller-afb/README.md b/Controller-afb/README.md new file mode 100644 index 0000000..403f637 --- /dev/null +++ b/Controller-afb/README.md @@ -0,0 +1,333 @@ +Controler AAAA(AGL Advance Audio Controler) and more. +------------------------------------------------------------ + + * Object: Generic Controler to handle Policy,Small Business Logic, Glue in between components, ... + * Status: Release Candidate + * Author: Fulup Ar Foll fulup@iot.bzh + * Date : August-2017 + +## Functionalities: + - Create an application dedicate controller from a JSON config file + - Each controls (eg: navigation, multimedia, ...) is a suite of actions. When all actions succeed control is granted, if one fail control acces is denied. + - Actions can either be: + + Invocation to an other binding API, either internal or external (eg: a policy service, Alsa UCM, ...) + + C routines from a user provider plugin (eg: policy routine, proprietary code, ...) + + Lua script function. Lua provides access to every AGL appfw functionalities and can be extended from C user provided plugins. + +## Installation + - Controler is a native part of AGL Advance Audio Framework but may be used independently with any other service or application binder. + - Dependencies: the only dependencies are audio-common for JSON-WRAP and Filescan-utils capabilities. + - Controler relies on Lua-5.3, when not needed Lua might be removed at compilation time. + +## Config + +Configuration is loaded dynamically during startup time. The controller scans CONTROL_CONFIG_PATH for a file corresponding to pattern +"onload-bindername-xxxxx.json". When controller runs within AAAA binder it searches for "onload-audio-xxxx.json". First file found in the path the loaded +any other files corresponding to the same pather are ignored and only generate a warning. + +Each bloc in the configuration file are defined with + * label: must be provided is used either for debugging or as input for the action (eg: signal name, control name, ...) + * info: optional used for documentation purpose only + +Note by default controller config search path is defined at compilation time, but path might be overloaded with CONTROL_CONFIG_PATH +environment variable. + +### Config is organised in 4 sections: + + * metadata + * onload defines the set of action to be executed at startup time + * control defines the set of controls with corresponding actions + * event define the set of actions to be executed when receiving a given signal + +### Metadata + +As today matadata is only used for documentation purpose. + * label + version mandatory + * info optional + +### OnLoad section + +Defines startup time configuration. Onload may provide multiple initialisation profiles, each with a different label. + * label is mandatory. Label is used to select onload profile at initialisation through DispatchOneOnLoad("onload-label") API; + * info is optional + * plugin provides optional unique plugin name. Plugin should follow "onload-bindername-xxxxx.ctlso" patern + and are search into CONTROL_PLUGIN_PATH. When defined controller will execute user provided function context=CTLP_ONLOAD(label,version,info). + The context returned by this routine is provided back to any C routines call later by the controller. Note that Lua2C function + are prefix in Lua script with plugin label (eg: MyPlug: in following config sample) + * lua2c list of Lua commands shipped with provided plugin. + * require list of binding that should be initialised before the controller starts. Note that some listed requirer binding might be absent, + nevertheless any present binding from this list will be started before controller binding, missing ones generate a warning. + * action the list of action to execute during loadtime. Any failure in action will prevent controller binding from starting. + +### Control section + +Defines a list of controls that are accessible through (api="control", verb="request", control="control-label"). + + * label mandatory + * info optional + * permissions Cynara needed privileges to request this control (same as AppFw-V2) + * action the list of actions + +### Event section + +Defines a list of actions to be executed on event reception. Even can do anything a controller can (change state, +send back signal, ...) eg: if a controller subscribes to vehicule speed, then speed-event may ajust master-volume to speed. + + * label mandatory + * info optional + * action the list of actions + +### Actions Categories + +Controler support tree categories of actions. Each action return a status status where 0=success and 1=failure. + * AppFw API, Provides a generic model to request other bindings. Requested binding can be local (eg: ALSA/UCM) or + external (eg: vehicle signalling). + * api provides requested binding API name + * verb provides verb to requested binding + * args optionally provides a jsonc object for targeted binding API. Note that 'args' are statically defined + in JSON configuration file. Controler client may also provided its own arguments from the query list. Targeted + binding receives both arguments defined in the config file and the argument provided by controller client. + * C-API, when defined in the onload section, the plugin may provided C native API with CTLP-CAPI(apiname, label, args, query, context). + Plugin may also create Lua command with CTLP-Lua2C(LuaFuncName, label, args, query, context). Where args+query are JSONC object + and context the value return from CTLP_ONLOAD function. Any missing value is set to NULL. + * Lua-API, when compiled with Lua option, the controller support action defined directly in Lua script. During "onload" phase the + controller search in CONTROL_Lua_PATH file with pattern "onload-bindername-xxxx.lua". Any file corresponding to this pattern + is automatically loaded. Any function defined in those Lua script can be called through a controller action. Lua functions receive + three parameters (label, args, query). + +Note: Lua added functions systematically prefix. AGL standard AppFw functions are prefixed with AGL: (eg: AGL:notice(), AGL_success(), ...). +User Lua functions added though the plugin and CTLP_Lua2C are prefix with plugin label (eg: MyPlug:HelloWorld1). + +### Avaliable Application Framework Commands + +Each Lua AppFw commands should be prefixed by AFB: + + * AFB:notice ("format", arg1,... argn) LUA table are print directly as json string with '%s'. + AFB:error, AFB:warning, AFB:info, AFB:debug work on the same model. Printed message are limited to 512 characters. + + * AFB:service ('API', 'VERB', {query}, "Lua_Callback_Name", {context}) asynchronous call to an other binding. When empty query/context should be set to '{}' + and not to 'nil'. When 'nil' Lua does not send 'NULL' value but remove arguments to calling stack. WARNING:"Callback" + is the name of the callback as a string and not a pointer to the callback. (If someone as a solution to fix this, please + let me known). Callback is call as LUA "function Alsa_Get_Hal_CB (error, result, context)" where: + * error is a Boolean + * result is the full answer from AppFw (do not forget to extract response) + * context is a copy of the Lua table pas as argument (warning it's a copy not a pointer to original table) + + * error,result=AFB:servsync('API', 'VERB', {query}) Save as previous but for synchronous call. Note that Lua accept multiple + return. AFB:servsync return both the error message and the response as a Lua table. Like for AFB:service user should not + forget to extract response from result. + + * AFB:success(request, response) request is the opaque handle pass when Lua is called from (api="control", verb="docall"). + Response is a Lua table that will be return to client. + + * AFB:fail(request, response) same as for success. Note that LUA generate automatically the error code from Lua function name. + The response is tranformed to a json string before being return to client. + + * EventHandle=AFB:evtmake("MyEventName") Create an event and return the handle as an opaque handle. Note that due to a limitation + of json_object this opaque handle cannot be passed as argument in a callback context. + + * AFB:subscribe(request, MyEventHandle) Subscribe a given client to previously created event. + + * AFB:evtpush (MyEventHandle, MyEventData) Push an event to every subscribed client. MyEventData is a Lua table that will be + send as a json object to corresponding clients. + + * timerHandle=AFB:timerset (MyTimer, "Timer_Test_CB", context) Initialise a timer from MyTimer Lua table. This table should contend 3 elements: + MyTimer={[l"abel"]="MyTimerName", ["delay"]=timeoutInMs, ["count"]=nBOfCycles}. Note that is count==0 then timer is cycle + infinitively. Context is a standard Lua table. This function return an opaque handle to be use to further control the timer. + + * AFB:timerclear(timerHandle) Kill an existing timer. Return an error when timer does not exit. + + * MyTimer=AFB:timerget(timerHandle) Return Label, Delay and Count of an active timer. Return an error when timerHandle does not + point on an active timer. + +Note: Except for function call during binding initialisation period. Lua call are protected and should return clean message + even when improperly used. If you find bug please report. + +### Adding Lua command from User Plugin + +User Plugin is optional and may provide either native C-action accessible directly from controller actions as defined in +JSON config file, or alternatively may provide at set of Lua commands usable inside any script (onload, control,event). A simple +plugin that provide both natice C API and Lua commands is provided as example (see ctl-plugin-sample.c). Technically a +plugin is a simple sharelibrary and any code fitting in sharelib might be used as a plugin. Developer should nevertheless +not forget that except when no-concurrency flag was at binding construction time, any binding should to be thread safe. + +A plugin must be declare with CTLP_REGISTER("MyCtlSamplePlugin"). This entry point defines a special structure that is check +at plugin load time by the controller. Then you have an optional init routine declare with CTLP_ONLOAD(label, version, info). +This init routine receives controller onload profile as selected by DispatchOnLoad("profile"). The init routine may create +a plugin context that is later one presented to every plugin API this for both LUA and native C ones. Then each: + + * C API declare with CTLP_CAPI (MyCFunction, label, argsJ, queryJ, context) {your code}. Where: + * MyFunction is your function + * Label is a string containing the name of your function + * ArgsJ a json_object containing the argument attach the this control in JSON config file. + * context your C context as return from CTLP_ONLOAD + + * Lua API declarewith TLP_LUA2C (MyLuaCFunction, label, argsJ, context) {your code}. Where + * MyLuaCFunction is both the name of your C function and Lua command + * Label your function name as a string + * Args the arguments passed this time from Lua script and not from Json config file. + * Query is not provided as LuaC function are called from a script and not directly from controller action list. + +Warning: Lua samples use with controller enforce strict mode. As a result every variables should be declare either as +local or as global. Unfortunately "luac" is not smart enough to handle strict mode at build time and errors only appear +at run time. Because of this strict mode every global variables (which include functions) should be prefix by '_'. +Note that LUA require an initialisation value for every variables and declaring something like "local myvar" wont +allocate "myvar" + +### Debugging Facilities + +Controler Lua script are check for syntax from CMAKE template with Luac. When needed to go further an developer API allow to +execute directly Lua command within controller context from Rest/Ws (api=control, verb=lua_doscript). DoScript API takes two +other optional arguments func=xxxx where xxxx is the function to execute within Lua script and args a JSON object to provide +input parameter. When funcname is not given by default the controller try to execute middle filename doscript-xxxx-????.lua. + +When executed from controller Lua script may use any AppFw Apis as well as any L2C user defined commands in plugin. + +## Config Sample + +Here after a simple configuration sample. + +``` +{ + "$schema": "ToBeDone", + "metadata": { + "label": "sample-audio-control", + "info": "Provide Default Audio Policy for Multimedia, Navigation and Emergency", + "version": "1.0" + }, + "onload": [{ + "label": "onload-default", + "info": "onload initialisation config", + "plugin": { + "label" : "MyPlug", + "sharelib": "ctl-audio-plugin-sample.ctlso", + "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] + }, + "require": ["intel-hda", "jabra-usb", "scarlett-usb"], + "actions": [ + { + "label": "onload-sample-cb", + "info": "Call control sharelib install entrypoint", + "callback": "SamplePolicyInit", + "args": { + "arg1": "first_arg", + "nextarg": "second arg value" + } + }, { + "label": "onload-sample-api", + "info": "Assert AlsaCore Presence", + "api": "alsacore", + "verb": "ping", + "args": "test" + }, { + "label": "onload-hal-lua", + "info": "Load avaliable HALs", + "lua": "Audio_Init_Hal" + } + ] + }], + "controls": + [ + { + "label": "multimedia", + "permissions": "urn:AGL:permission:audio:public:mutimedia", + "actions": { + "label": "multimedia-control-lua", + "info": "Call Lua Script function Test_Lua_Engin", + "lua": "Audio_Set_Multimedia" + } + }, { + "label": "navigation", + "permissions": "urn:AGL:permission:audio:public:navigation", + "actions": { + "label": "navigation-control-lua", + "info": "Call Lua Script to set Navigation", + "lua": "Audio_Set_Navigation" + } + }, { + "label": "emergency", + "permissions": "urn:AGL:permission:audio:public:emergency", + "actions": { + "label": "emergency-control-ucm", + "lua": "Audio_Set_Emergency" + } + }, { + "label": "multi-step-sample", + "info" : "all actions must succeed for control to be accepted", + "actions": [{ + "label": "multimedia-control-cb", + "info": "Call Sharelib Sample Callback", + "callback": "sampleControlNavigation", + "args": { + "arg1": "snoopy", + "arg2": "toto" + } + }, { + "label": "navigation-control-ucm", + "api": "alsacore", + "verb": "ping", + "args": { + "test": "navigation" + } + }, { + "label": "navigation-control-lua", + "info": "Call Lua Script to set Navigation", + "lua": "Audio_Set_Navigation" + }] + } + ], + "events": + [ + { + "label": "Vehicle-Speed", + "info": "Action when Vehicule speed change", + "actions": [ + { + "label": "speed-action-1", + "callback": "Blink-when-over-130", + "args": { + "speed": 130 + "blink-speed": 1000 + } + }, { + "label": "Adjust-Volume", + "lua": "Adjust_Volume_To_Speed", + } + ] + }, + { + "label": "Reverse-Engage", + "info": "When Reverse Gear is Engage", + "actions": [ + { + "label": "Display-Rear-Camera", + "callback": "Display-Rear-Camera", + }, { + "label": "Prevent-Phone-Call", + "api" : "phone", + "verb" : "status", + "args": { + "call-accepted": false + } + } + ] + }, + { + "label": "Neutral-Engage", + "info": "When Reverse Neutral is Engage", + "actions": [ + { + "label": "Authorize-Video", + "api" : "video", + "verb" : "status", + "args": { + "tv-accepted": true + } + } + ] + } + ] +} + +``` + diff --git a/Controller-afb/a.out b/Controller-afb/a.out new file mode 100755 index 0000000..d18064f Binary files /dev/null and b/Controller-afb/a.out differ diff --git a/Controller-afb/ctl-apidef.h b/Controller-afb/ctl-apidef.h new file mode 100644 index 0000000..68f9725 --- /dev/null +++ b/Controller-afb/ctl-apidef.h @@ -0,0 +1,115 @@ + +static const char _afb_description_v2_control[] = + "{\"openapi\":\"3.0.0\",\"$schema\":\"http:iot.bzh/download/openapi/schem" + "a-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\"c" + "ontroler\",\"version\":\"1.0\",\"x-binding-c-generator\":{\"api\":\"cont" + "rol\",\"version\":2,\"prefix\":\"ctlapi_\",\"postfix\":\"\",\"start\":nu" + "ll,\"onevent\":\"DispatchOneEvent\",\"init\":\"CtlBindingInit\",\"scope\"" + ":\"\",\"private\":false}},\"servers\":[{\"url\":\"ws://{host}:{port}/api" + "/polctl\",\"description\":\"Unicens2 API.\",\"variables\":{\"host\":{\"d" + "efault\":\"localhost\"},\"port\":{\"default\":\"1234\"}},\"x-afb-events\"" + ":[{\"$ref\":\"#/components/schemas/afb-event\"}]}],\"components\":{\"sch" + "emas\":{\"afb-reply\":{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\"" + "afb-event\":{\"$ref\":\"#/components/schemas/afb-event-v2\"},\"afb-reply" + "-v2\":{\"title\":\"Generic response.\",\"type\":\"object\",\"required\":" + "[\"jtype\",\"request\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"" + "const\":\"afb-reply\"},\"request\":{\"type\":\"object\",\"required\":[\"" + "status\"],\"properties\":{\"status\":{\"type\":\"string\"},\"info\":{\"t" + "ype\":\"string\"},\"token\":{\"type\":\"string\"},\"uuid\":{\"type\":\"s" + "tring\"},\"reqid\":{\"type\":\"string\"}}},\"response\":{\"type\":\"obje" + "ct\"}}},\"afb-event-v2\":{\"type\":\"object\",\"required\":[\"jtype\",\"" + "event\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-" + "event\"},\"event\":{\"type\":\"string\"},\"data\":{\"type\":\"object\"}}" + "}},\"x-permissions\":{\"monitor\":{\"permission\":\"urn:AGL:permission:a" + "udio:public:monitor\"},\"multimedia\":{\"permission\":\"urn:AGL:permissi" + "on:audio:public:monitor\"},\"navigation\":{\"permission\":\"urn:AGL:perm" + "ission:audio:public:monitor\"},\"emergency\":{\"permission\":\"urn:AGL:p" + "ermission:audio:public:emergency\"}},\"responses\":{\"200\":{\"descripti" + "on\":\"A complex object array response\",\"content\":{\"application/json" + "\":{\"schema\":{\"$ref\":\"#/components/schemas/afb-reply\"}}}}}},\"path" + "s\":{\"/monitor\":{\"description\":\"Subcribe Audio Agent Policy Control" + " End\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions" + "/monitor\"},\"parameters\":[{\"in\":\"query\",\"name\":\"event_patern\"," + "\"required\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"20" + "0\":{\"$ref\":\"#/components/responses/200\"}}}},\"/dispatch\":{\"descri" + "ption\":\"Request Access to Navigation Audio Channel.\",\"get\":{\"x-per" + "missions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"parame" + "ters\":[{\"in\":\"query\",\"name\":\"zone\",\"required\":false,\"schema\"" + ":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components" + "/responses/200\"}}}},\"/lua_docall\":{\"description\":\"Execute LUA stri" + "ng script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permi" + "ssions/navigation\"},\"parameters\":[{\"in\":\"query\",\"name\":\"func\"" + ",\"required\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"query\",\"" + "name\":\"args\",\"required\":false,\"schema\":{\"type\":\"array\"}}],\"r" + "esponses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_" + "dostring\":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-" + "permissions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"par" + "ameters\":[{\"in\":\"query\",\"required\":true,\"schema\":{\"type\":\"st" + "ring\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"" + "}}}},\"/lua_doscript\":{\"description\":\"Execute LUA string script.\",\"" + "get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/navigati" + "on\"},\"parameters\":[{\"in\":\"query\",\"name\":\"filename\",\"required" + "\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$re" + "f\":\"#/components/responses/200\"}}}}}}" +; + +static const struct afb_auth _afb_auths_v2_control[] = { + { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:monitor" } +}; + + void ctlapi_monitor(struct afb_req req); + void ctlapi_dispatch(struct afb_req req); + void ctlapi_lua_docall(struct afb_req req); + void ctlapi_lua_dostring(struct afb_req req); + void ctlapi_lua_doscript(struct afb_req req); + +static const struct afb_verb_v2 _afb_verbs_v2_control[] = { + { + .verb = "monitor", + .callback = ctlapi_monitor, + .auth = &_afb_auths_v2_control[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { + .verb = "dispatch", + .callback = ctlapi_dispatch, + .auth = &_afb_auths_v2_control[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { + .verb = "lua_docall", + .callback = ctlapi_lua_docall, + .auth = &_afb_auths_v2_control[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { + .verb = "lua_dostring", + .callback = ctlapi_lua_dostring, + .auth = &_afb_auths_v2_control[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { + .verb = "lua_doscript", + .callback = ctlapi_lua_doscript, + .auth = &_afb_auths_v2_control[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { .verb = NULL } +}; + +const struct afb_binding_v2 afbBindingV2 = { + .api = "control", + .specification = _afb_description_v2_control, + .info = NULL, + .verbs = _afb_verbs_v2_control, + .preinit = NULL, + .init = CtlBindingInit, + .onevent = DispatchOneEvent, + .noconcurrency = 0 +}; + diff --git a/Controller-afb/ctl-apidef.json b/Controller-afb/ctl-apidef.json new file mode 100644 index 0000000..c35cbc0 --- /dev/null +++ b/Controller-afb/ctl-apidef.json @@ -0,0 +1,250 @@ +{ + "openapi": "3.0.0", + "$schema": "http:iot.bzh/download/openapi/schema-3.0/default-schema.json", + "info": { + "description": "", + "title": "controler", + "version": "1.0", + "x-binding-c-generator": { + "api": "control", + "version": 2, + "prefix": "ctlapi_", + "postfix": "", + "start": null, + "onevent": "DispatchOneEvent", + "init": "CtlBindingInit", + "scope": "", + "private": false + } + }, + "servers": [ + { + "url": "ws://{host}:{port}/api/polctl", + "description": "Unicens2 API.", + "variables": { + "host": { + "default": "localhost" + }, + "port": { + "default": "1234" + } + }, + "x-afb-events": [ + { + "$ref": "#/components/schemas/afb-event" + } + ] + } + ], + "components": { + "schemas": { + "afb-reply": { + "$ref": "#/components/schemas/afb-reply-v2" + }, + "afb-event": { + "$ref": "#/components/schemas/afb-event-v2" + }, + "afb-reply-v2": { + "title": "Generic response.", + "type": "object", + "required": ["jtype", "request"], + "properties": { + "jtype": { + "type": "string", + "const": "afb-reply" + }, + "request": { + "type": "object", + "required": ["status"], + "properties": { + "status": { + "type": "string" + }, + "info": { + "type": "string" + }, + "token": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "reqid": { + "type": "string" + } + } + }, + "response": { + "type": "object" + } + } + }, + "afb-event-v2": { + "type": "object", + "required": ["jtype", "event"], + "properties": { + "jtype": { + "type": "string", + "const": "afb-event" + }, + "event": { + "type": "string" + }, + "data": { + "type": "object" + } + } + } + }, + "x-permissions": { + "monitor": { + "permission": "urn:AGL:permission:audio:public:monitor" + }, + "multimedia": { + "permission": "urn:AGL:permission:audio:public:monitor" + }, + "navigation": { + "permission": "urn:AGL:permission:audio:public:monitor" + }, + "emergency": { + "permission": "urn:AGL:permission:audio:public:emergency" + } + }, + "responses": { + "200": { + "description": "A complex object array response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/afb-reply" + } + } + } + } + } + }, + "paths": { + "/monitor": { + "description": "Subcribe Audio Agent Policy Control End", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/monitor" + }, + "parameters": [ + { + "in": "query", + "name": "event_patern", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200" + } + } + } + }, + "/dispatch": { + "description": "Request Access to Navigation Audio Channel.", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/navigation" + }, + "parameters": [ + { + "in": "query", + "name": "zone", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200" + } + } + } + }, + "/lua_docall": { + "description": "Execute LUA string script.", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/navigation" + }, + "parameters": [ + { + "in": "query", + "name": "func", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "args", + "required": false, + "schema": { + "type": "array" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200" + } + } + } + }, + "/lua_dostring": { + "description": "Execute LUA string script.", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/navigation" + }, + "parameters": [ + { + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200" + } + } + } + }, + "/lua_doscript": { + "description": "Execute LUA string script.", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/navigation" + }, + "parameters": [ + { + "in": "query", + "name": "filename", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200" + } + } + } + } + } +} diff --git a/Controller-afb/ctl-binding.c b/Controller-afb/ctl-binding.c new file mode 100644 index 0000000..8771fc0 --- /dev/null +++ b/Controller-afb/ctl-binding.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "audio-common.h" +#include "ctl-binding.h" + + + +// Include Binding Stub generated from Json OpenAPI +#include "ctl-apidef.h" + + +PUBLIC void ctlapi_monitor (afb_req request) { + + // subscribe Client to event + int err = afb_req_subscribe(request, TimerEvtGet()); + if (err != 0) { + afb_req_fail_f(request, "register-event", "Fail to subscribe binder event"); + goto OnErrorExit; + } + + afb_req_success(request, NULL, NULL); + + OnErrorExit: + return; +} + +// Create Binding Event at Init +PUBLIC int CtlBindingInit () { + + int errcount=0; + + errcount += TimerEvtInit(); + errcount += DispatchInit(); +#ifdef CONTROL_SUPPORT_LUA + errcount += LuaLibInit(); +#endif + + // now that everything is initialised execute the onload action + if (!errcount) + errcount += DispatchOnLoad(CONTROL_ONLOAD_DEFAULT); + + AFB_DEBUG ("Audio Policy Control Binding Done errcount=%d", errcount); + return errcount; +} + diff --git a/Controller-afb/ctl-binding.h b/Controller-afb/ctl-binding.h new file mode 100644 index 0000000..a1c7ef2 --- /dev/null +++ b/Controller-afb/ctl-binding.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CONTROLLER_BINDING_INCLUDE +#define CONTROLLER_BINDING_INCLUDE + +#define AFB_BINDING_VERSION 2 +#include +#include +#include +#include +#include + + +#ifdef CONTROL_SUPPORT_LUA +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#endif + +#ifndef PUBLIC + #define PUBLIC +#endif +#define STATIC static + +#ifndef UNUSED_ARG +#define UNUSED_ARG(x) UNUSED_ ## x __attribute__((__unused__)) +#define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x +#endif + +// polctl-binding.c +PUBLIC int CtlBindingInit (); + +// ctl-timerevt.c +// ---------------------- +typedef int (*timerCallbackT)(void *context); + +typedef struct TimerHandleS { + int count; + int delay; + const char*label; + void *context; + timerCallbackT callback; + sd_event_source *evtSource; +} TimerHandleT; + +PUBLIC int TimerEvtInit (void); +PUBLIC afb_event TimerEvtGet(void); +PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context); +PUBLIC void TimerEvtStop(TimerHandleT *timerHandle); + +// ctl-policy +// ----------- + +typedef enum { + CTL_MODE_NONE=0, + CTL_MODE_API, + CTL_MODE_CB, + CTL_MODE_LUA, +} CtlRequestModeT; + + +typedef enum { + CTL_SOURCE_CLOSE=-1, + CTL_SOURCE_UNKNOWN=0, + CTL_SOURCE_ONLOAD=1, + CTL_SOURCE_OPEN=2, + CTL_SOURCE_EVENT=3, +} DispatchSourceT; + +typedef struct DispatchActionS{ + const char *info; + const char* label; + CtlRequestModeT mode; + const char* api; + const char* call; + json_object *argsJ; + int timeout; + int (*actionCB)(DispatchSourceT source, const char*label, json_object *argsJ, json_object *queryJ, void *context); +} DispatchActionT; + +typedef int (*Lua2cFunctionT)(char *funcname, json_object *argsJ, void*context); + +PUBLIC int DispatchInit(void); +PUBLIC int DispatchOnLoad(const char *onLoadLabel); +PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ); +PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback); +PUBLIC void ctlapi_dispatch (afb_req request); + +#ifdef CONTROL_SUPPORT_LUA +// ctl-lua.c +typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunctionT callback); + +#define CTLP_LUA2C(FuncName, label,argsJ, context) static int FuncName(char*label,json_object*argsJ, void*context);\ + int lua2c_ ## FuncName(lua_State* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(FuncName), FuncName));};\ + static int FuncName(char* label, json_object* argsJ, void* context) + +typedef enum { + LUA_DOCALL, + LUA_DOSTRING, + LUA_DOSCRIPT, +} LuaDoActionT; + +PUBLIC int LuaLibInit (); +PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count); +PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context); +PUBLIC int LuaCallFunc (DispatchSourceT source, DispatchActionT *action, json_object *queryJ) ; +PUBLIC void ctlapi_lua_docall (afb_req request); +PUBLIC void ctlapi_lua_dostring (afb_req request); +PUBLIC void ctlapi_lua_doscript (afb_req request); + +#else + typedef void* Lua2cWrapperT; +#endif // CONTROL_SUPPORT_LUA + + +// sharelib ctl-plugin* +typedef struct { + long magic; + char *label; +} CtlPluginMagicT; + + +#define MACRO_STR_VALUE(arg) #arg +#define CTLP_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; Lua2cWrapperT Lua2cWrap; +#define CTLP_ONLOAD(label,version,info) void* CtlPluginOnload(char* label, char* version, char* info) +#define CTLP_CAPI(funcname,source, label,argsJ, queryJ, context) int funcname(DispatchSourceT source, char* label, json_object* argsJ, json_object* queryJ, void* context) + + + +#endif // CONTROLLER_BINDING_INCLUDE diff --git a/Controller-afb/ctl-dispatch.c b/Controller-afb/ctl-dispatch.c new file mode 100644 index 0000000..1708204 --- /dev/null +++ b/Controller-afb/ctl-dispatch.c @@ -0,0 +1,665 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, something express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Reference: + * Json load using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "ctl-binding.h" + +typedef void*(*DispatchPluginInstallCbT)(const char* label, const char*version, const char*info); + + +static afb_req NULL_AFBREQ = {}; + + +typedef struct { + const char* label; + const char *info; + DispatchActionT *actions; +} DispatchHandleT; + +typedef struct { + const char *label; + const char *info; + void *context; + char *sharelib; + void *dlHandle; + luaL_Reg *l2cFunc; + int l2cCount; +} DispatchPluginT; + +typedef struct { + const char* label; + const char *info; + const char *version; + DispatchPluginT *plugin; + DispatchHandleT **onloads; + DispatchHandleT **events; + DispatchHandleT **controls; +} DispatchConfigT; + +// global config handle +STATIC DispatchConfigT *configHandle = NULL; + +STATIC int DispatchControlToIndex(DispatchHandleT **controls, const char* controlLabel) { + + for (int idx = 0; controls[idx]; idx++) { + if (!strcasecmp(controlLabel, controls[idx]->label)) return idx; + } + return -1; +} + +STATIC int DispatchOneControl(DispatchSourceT source, DispatchHandleT **controls, const char* controlLabel, json_object *queryJ, afb_req request) { + int err; + + if (!configHandle) { + AFB_ERROR("DISPATCH-CTL-API: (Hoops/Bug!!!) No Config Loaded"); + goto OnErrorExit; + } + + if (!configHandle->controls) { + AFB_ERROR("DISPATCH-CTL-API: No Control Action in Json config label=%s version=%s", configHandle->label, configHandle->version); + goto OnErrorExit; + } + + int index = DispatchControlToIndex(controls, controlLabel); + if (index < 0 || !controls[index]->actions) { + AFB_ERROR("DISPATCH-CTL-API:NotFound/Error label=%s in Json Control Config File", controlLabel); + goto OnErrorExit; + } + + // Fulup (Bug/Feature) in current version is unique to every onload profile + if (configHandle->plugin && configHandle->plugin->l2cCount) { + LuaL2cNewLib (configHandle->plugin->label, configHandle->plugin->l2cFunc, configHandle->plugin->l2cCount); + } + + // loop on action for this control + DispatchActionT *actions = controls[index]->actions; + for (int idx = 0; actions[idx].label; idx++) { + + switch (actions[idx].mode) { + case CTL_MODE_API: + { + json_object *returnJ; + + // if query is empty increment usage count and pass args + if (!queryJ || json_object_get_type(queryJ) != json_type_object) { + json_object_get(actions[idx].argsJ); + queryJ= actions[idx].argsJ; + } else if (actions[idx].argsJ) { + + // Merge queryJ and argsJ before sending request + if (json_object_get_type(actions[idx].argsJ) == json_type_object) { + json_object_object_foreach(actions[idx].argsJ, key, val) { + json_object_object_add(queryJ, key, val); + } + } else { + json_object_object_add(queryJ, "args", actions[idx].argsJ); + } + } + + int err = afb_service_call_sync(actions[idx].api, actions[idx].call, queryJ, &returnJ); + if (err) { + static const char*format = "DispatchOneControl(Api) api=%s verb=%s args=%s"; + if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:API", format, actions[idx].label, actions[idx].api, actions[idx].call); + else AFB_ERROR(format, actions[idx].api, actions[idx].call, actions[idx].label); + goto OnErrorExit; + } + break; + } + +#ifdef CONTROL_SUPPORT_LUA + case CTL_MODE_LUA: + err = LuaCallFunc(source, &actions[idx], queryJ); + if (err) { + static const char*format = "DispatchOneControl(Lua) label=%s func=%s args=%s"; + if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Lua", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + goto OnErrorExit; + } + break; +#endif + + case CTL_MODE_CB: + err = (*actions[idx].actionCB) (source, actions[idx].label, actions[idx].argsJ, queryJ, configHandle->plugin->context); + if (err) { + static const char*format = "DispatchOneControl(Callback) label%s func=%s args=%s"; + if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Cb", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ)); + goto OnErrorExit; + } + break; + + default: + { + static const char*format = "DispatchOneControl(unknown) mode control=%s action=%s"; + AFB_ERROR(format, controls[index]->label); + if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:Unknown", format, controls[index]->label); + } + } + } + + // everything when fine + if (afb_req_is_valid(request))afb_req_success(request, NULL, controls[index]->label); + return 0; + +OnErrorExit: + return -1; +} + + +// Event name is mapped on control label and executed as a standard control + +PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ) { + DispatchHandleT **events = configHandle->events; + + (void) DispatchOneControl(CTL_SOURCE_EVENT, events, evtLabel, eventJ, NULL_AFBREQ); +} + +// Event name is mapped on control label and executed as a standard control + +PUBLIC int DispatchOnLoad(const char *onLoadLabel) { + DispatchHandleT **onloads = configHandle->onloads; + + int err = DispatchOneControl(CTL_SOURCE_ONLOAD, onloads, onLoadLabel, NULL, NULL_AFBREQ); + return err; +} + +PUBLIC void ctlapi_dispatch(afb_req request) { + DispatchHandleT **controls = configHandle->controls; + json_object *queryJ, *argsJ=NULL; + const char *target; + DispatchSourceT source= CTL_SOURCE_UNKNOWN; + + queryJ = afb_req_json(request); + int err = wrap_json_unpack(queryJ, "{s:s, s?i s?o !}", "target", &target, "source", &source, "args", &argsJ); + if (err) { + afb_req_fail_f(request, "CTL-DISPTACH-INVALID", "missing target or args not a valid json object query=%s", json_object_get_string(queryJ)); + goto OnErrorExit; + } + + (void) DispatchOneControl(source, controls, target, argsJ, request); + +OnErrorExit: + return; +} + +// Wrapper to Lua2c plugin command add context dans delegate to LuaWrapper +PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback) { +#ifndef CONTROL_SUPPORT_LUA + AFB_ERROR("DISPATCH-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake"); + return 1; +#else + int err=Lua2cWrapper(luaState, funcname, callback, configHandle->plugin->context); + return err; +#endif +} + + +// List Avaliable Configuration Files + +PUBLIC void ctlapi_config(struct afb_req request) { + json_object*tmpJ; + char *dirList; + + + json_object* queryJ = afb_req_json(request); + if (queryJ && json_object_object_get_ex(queryJ, "cfgpath", &tmpJ)) { + dirList = strdup(json_object_get_string(tmpJ)); + } else { + + dirList = getenv("CONTROL_CONFIG_PATH"); + if (!dirList) dirList = strdup(CONTROL_CONFIG_PATH); + AFB_NOTICE("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH); + } + + // get list of config file + struct json_object *responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, "onload", "json"); + + if (json_object_array_length(responseJ) == 0) { + afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH"); + } else { + afb_req_success(request, responseJ, NULL); + } + + return; +} + +// unpack individual action object + +STATIC int DispatchLoadOneAction(DispatchConfigT *controlConfig, json_object *actionJ, DispatchActionT *action) { + char *api = NULL, *verb = NULL, *callback = NULL, *lua = NULL; + int err, modeCount = 0; + + err = wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s,s?o !}" + , "label", &action->label, "info", &action->info, "callback", &callback, "lua", &lua, "api", &api, "verb", &verb, "args", &action->argsJ); + if (err) { + AFB_ERROR("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ)); + goto OnErrorExit; + } + + if (lua) { + action->mode = CTL_MODE_LUA; + action->call = lua; + modeCount++; + } + + if (api && verb) { + action->mode = CTL_MODE_API; + action->api = api; + action->call = verb; + modeCount++; + } + + if (callback && controlConfig->plugin) { + action->mode = CTL_MODE_CB; + action->call = callback; + modeCount++; + + action->actionCB = dlsym(controlConfig->plugin->dlHandle, callback); + if (!action->actionCB) { + AFB_ERROR("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, controlConfig->plugin->sharelib); + goto OnErrorExit; + } + } + + // make sure at least one mode is selected + if (modeCount == 0) { + AFB_ERROR("DISPATCH-LOAD-ACTION No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); + goto OnErrorExit; + } + + if (modeCount > 1) { + AFB_ERROR("DISPATCH-LOAD-ACTION:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); + goto OnErrorExit; + } + return 0; + +OnErrorExit: + return -1; +}; + +STATIC DispatchActionT *DispatchLoadActions(DispatchConfigT *controlConfig, json_object *actionsJ) { + int err; + DispatchActionT *actions; + + // action array is close with a nullvalue; + if (json_object_get_type(actionsJ) == json_type_array) { + int count = json_object_array_length(actionsJ); + actions = calloc(count + 1, sizeof (DispatchActionT)); + + for (int idx = 0; idx < count; idx++) { + json_object *actionJ = json_object_array_get_idx(actionsJ, idx); + err = DispatchLoadOneAction(controlConfig, actionJ, &actions[idx]); + if (err) goto OnErrorExit; + } + + } else { + actions = calloc(2, sizeof (DispatchActionT)); + err = DispatchLoadOneAction(controlConfig, actionsJ, &actions[0]); + if (err) goto OnErrorExit; + } + + return actions; + +OnErrorExit: + return NULL; + +} + +STATIC DispatchHandleT *DispatchLoadControl(DispatchConfigT *controlConfig, json_object *controlJ) { + json_object *actionsJ, *permissionsJ; + int err; + + DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT)); + err = wrap_json_unpack(controlJ, "{ss,s?s,s?o, so !}", "label", &dispatchHandle->label, "info", &dispatchHandle->info + , "permissions", &permissionsJ, "actions", &actionsJ); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ)); + goto OnErrorExit; + } + + dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ); + if (!dispatchHandle->actions) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label); + goto OnErrorExit; + } + return dispatchHandle; + +OnErrorExit: + return NULL; +} + +STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_object *onloadJ) { + json_object *actionsJ = NULL, *requireJ = NULL, *pluginJ = NULL; + int err; + + DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT)); + err = wrap_json_unpack(onloadJ, "{ss,s?s, s?o,s?o,s?o !}", + "label", &dispatchHandle->label, "info", &dispatchHandle->info, "plugin", &pluginJ, "require", &requireJ, "actions", &actionsJ); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ)); + goto OnErrorExit; + } + + // best effort to initialise everything before starting + if (requireJ) { + + void DispatchRequireOneApi(json_object * bindindJ) { + const char* requireBinding = json_object_get_string(bindindJ); + err = afb_daemon_require_api(requireBinding, 1); + if (err) { + AFB_WARNING("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding); + } + } + + if (json_object_get_type(requireJ) == json_type_array) { + for (int idx = 0; idx < json_object_array_length(requireJ); idx++) { + DispatchRequireOneApi(json_object_array_get_idx(requireJ, idx)); + } + } else { + DispatchRequireOneApi(requireJ); + } + } + + if (pluginJ) { + json_object *lua2csJ = NULL; + DispatchPluginT *dPlugin= calloc(1, sizeof(DispatchPluginT)); + controlConfig->plugin = dPlugin; + const char*ldSearchPath=NULL; + + err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,ss,s?o!}", + "label", &dPlugin->label, "info", &dPlugin->info, "ldpath", &ldSearchPath, "sharelib", &dPlugin->sharelib, "lua2c", &lua2csJ); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Plugin missing label|[info]|sharelib|[lua2c] in %s", json_object_get_string(onloadJ)); + goto OnErrorExit; + } + + // if search path not in Json config file, then try default + if (!ldSearchPath) ldSearchPath=CONTROL_PLUGIN_PATH; + + // search for default policy config file + json_object *pluginPathJ = ScanForConfig(ldSearchPath, CTL_SCAN_RECURSIVE, dPlugin->sharelib, NULL); + if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", dPlugin->sharelib, ldSearchPath); + goto OnErrorExit; + } + + char *filename; + char*fullpath; + err = wrap_json_unpack(json_object_array_get_idx(pluginPathJ, 0), "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ)); + goto OnErrorExit; + } + + if (json_object_array_length(pluginPathJ) > 1) { + AFB_WARNING("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", fullpath, filename); + } + + char pluginpath[CONTROL_MAXPATH_LEN]; + strncpy(pluginpath, fullpath, sizeof (pluginpath)); + strncat(pluginpath, "/", sizeof (pluginpath)); + strncat(pluginpath, filename, sizeof (pluginpath)); + dPlugin->dlHandle = dlopen(pluginpath, RTLD_NOW); + if (!dPlugin->dlHandle) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror()); + goto OnErrorExit; + } + + CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*) dlsym(dPlugin->dlHandle, "CtlPluginMagic"); + if (!ctlPluginMagic || ctlPluginMagic->magic != CTL_PLUGIN_MAGIC) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath); + goto OnErrorExit; + } else { + AFB_NOTICE("DISPATCH-LOAD-CONFIG:Plugin %s successfully registered", ctlPluginMagic->label); + } + + // Jose hack to make verbosity visible from sharelib + struct afb_binding_data_v2 *afbHidenData = dlsym(dPlugin->dlHandle, "afbBindingV2data"); + if (afbHidenData) *afbHidenData = afbBindingV2data; + + // Push lua2cWrapper @ into plugin + Lua2cWrapperT *lua2cInPlug = dlsym(dPlugin->dlHandle, "Lua2cWrap"); +#ifndef CONTROL_SUPPORT_LUA + if (lua2cInPlug) *lua2cInPlug = NULL; +#else + // Lua2cWrapper is part of binder and not expose to dynamic link + if (lua2cInPlug) *lua2cInPlug = DispatchOneL2c; + + { + int Lua2cAddOne(luaL_Reg *l2cFunc, const char* l2cName, int index) { + char funcName[CONTROL_MAXPATH_LEN]; + strncpy(funcName, "lua2c_", sizeof(funcName)); + strncat(funcName, l2cName, sizeof(funcName)); + + Lua2cFunctionT l2cFunction= (Lua2cFunctionT)dlsym(dPlugin->dlHandle, funcName); + if (!l2cFunction) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'%s' missing err=%s", funcName, dlerror()); + return 1; + } + l2cFunc[index].func=(void*)l2cFunction; + l2cFunc[index].name=strdup(l2cName); + + return 0; + } + + int errCount = 0; + luaL_Reg *l2cFunc=NULL; + int count=0; + + // look on l2c command and push them to LUA + if (json_object_get_type(lua2csJ) == json_type_array) { + int length = json_object_array_length(lua2csJ); + l2cFunc = calloc(length + 1, sizeof (luaL_Reg)); + for (count=0; count < length; count++) { + int err; + const char *l2cName = json_object_get_string(json_object_array_get_idx(lua2csJ, count)); + err = Lua2cAddOne(l2cFunc, l2cName, count); + if (err) errCount++; + } + } else { + l2cFunc = calloc(2, sizeof (luaL_Reg)); + const char *l2cName = json_object_get_string(lua2csJ); + errCount = Lua2cAddOne(l2cFunc, l2cName, 0); + count=1; + } + if (errCount) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin %d symbols not found in plugin='%s'", errCount, pluginpath); + goto OnErrorExit; + } else { + dPlugin->l2cFunc= l2cFunc; + dPlugin->l2cCount= count; + } + } +#endif + DispatchPluginInstallCbT ctlPluginOnload = dlsym(dPlugin->dlHandle, "CtlPluginOnload"); + if (ctlPluginOnload) { + dPlugin->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info); + } + } + + dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ); + if (!dispatchHandle->actions) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchHandle->label); + goto OnErrorExit; + } + return dispatchHandle; + +OnErrorExit: + return NULL; +} + +STATIC DispatchConfigT *DispatchLoadConfig(const char* filepath) { + json_object *controlConfigJ, *ignoreJ; + int err; + + // Load JSON file + controlConfigJ = json_object_from_file(filepath); + if (!controlConfigJ) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath); + goto OnErrorExit; + } + + AFB_INFO("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath); + + json_object *metadataJ = NULL, *onloadsJ = NULL, *controlsJ = NULL, *eventsJ = NULL; + err = wrap_json_unpack(controlConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata", &metadataJ, "onload", &onloadsJ, "controls", &controlsJ, "events", &eventsJ); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(controlConfigJ)); + goto OnErrorExit; + } + + DispatchConfigT *controlConfig = calloc(1, sizeof (DispatchConfigT)); + if (metadataJ) { + err = wrap_json_unpack(metadataJ, "{ss,s?s,ss !}", "label", &controlConfig->label, "info", &controlConfig->info, "version", &controlConfig->version); + if (err) { + AFB_ERROR("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ)); + goto OnErrorExit; + } + } + + if (onloadsJ) { + DispatchHandleT *dispatchHandle; + + if (json_object_get_type(onloadsJ) != json_type_array) { + controlConfig->onloads = (DispatchHandleT**) calloc(2, sizeof (void*)); + dispatchHandle = DispatchLoadOnload(controlConfig, onloadsJ); + controlConfig->onloads[0] = dispatchHandle; + } else { + int length = json_object_array_length(onloadsJ); + controlConfig->onloads = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); + + for (int jdx = 0; jdx < length; jdx++) { + json_object *onloadJ = json_object_array_get_idx(onloadsJ, jdx); + dispatchHandle = DispatchLoadOnload(controlConfig, onloadJ); + controlConfig->onloads[jdx] = dispatchHandle; + } + } + } + + if (controlsJ) { + DispatchHandleT *dispatchHandle; + + if (json_object_get_type(controlsJ) != json_type_array) { + controlConfig->controls = (DispatchHandleT**) calloc(2, sizeof (void*)); + dispatchHandle = DispatchLoadControl(controlConfig, controlsJ); + controlConfig->controls[0] = dispatchHandle; + } else { + int length = json_object_array_length(controlsJ); + controlConfig->controls = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); + + for (int jdx = 0; jdx < length; jdx++) { + json_object *controlJ = json_object_array_get_idx(controlsJ, jdx); + dispatchHandle = DispatchLoadControl(controlConfig, controlJ); + controlConfig->controls[jdx] = dispatchHandle; + } + } + } + + if (eventsJ) { + DispatchHandleT *dispatchHandle; + + if (json_object_get_type(eventsJ) != json_type_array) { + controlConfig->events = (DispatchHandleT**) calloc(2, sizeof (void*)); + dispatchHandle = DispatchLoadControl(controlConfig, eventsJ); + controlConfig->events[0] = dispatchHandle; + } else { + int length = json_object_array_length(eventsJ); + controlConfig->events = (DispatchHandleT**) calloc(length + 1, sizeof (void*)); + + for (int jdx = 0; jdx < length; jdx++) { + json_object *eventJ = json_object_array_get_idx(eventsJ, jdx); + dispatchHandle = DispatchLoadControl(controlConfig, eventJ); + controlConfig->events[jdx] = dispatchHandle; + } + } + } + + return controlConfig; + +OnErrorExit: + return NULL; +} + + +// Load default config file at init + +PUBLIC int DispatchInit() { + int index, err, luaLoaded = 0; + char controlFile [CONTROL_MAXPATH_LEN]; + + const char *dirList= getenv("CONTROL_CONFIG_PATH"); + if (!dirList) dirList=CONTROL_CONFIG_PATH; + + strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN); + strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); + + // search for default dispatch config file + json_object* responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, controlFile, "json"); + + // We load 1st file others are just warnings + for (index = 0; index < json_object_array_length(responseJ); index++) { + json_object *entryJ = json_object_array_get_idx(responseJ, index); + + char *filename; + char*fullpath; + err = wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); + if (err) { + AFB_ERROR("DISPATCH-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); + goto OnErrorExit; + } + + if (index == 0) { + if (strcasestr(filename, controlFile)) { + char filepath[CONTROL_MAXPATH_LEN]; + strncpy(filepath, fullpath, sizeof (filepath)); + strncat(filepath, "/", sizeof (filepath)); + strncat(filepath, filename, sizeof (filepath)); + configHandle = DispatchLoadConfig(filepath); + if (!configHandle) { + AFB_ERROR("DISPATCH-INIT:ERROR Fail loading [%s]", filepath); + goto OnErrorExit; + } + luaLoaded = 1; + break; + } + } else { + AFB_WARNING("DISPATCH-INIT:WARNING Secondary Control Config Ignored %s/%s", fullpath, filename); + } + } + + // no dispatch config found remove control API from binder + if (!luaLoaded) { + AFB_WARNING("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile); + } + + AFB_NOTICE("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init"); + return 0; + +OnErrorExit: + AFB_NOTICE("DISPATCH-INIT:ERROR: Audio Control Dispatch Init"); + return 1; +} + + + diff --git a/Controller-afb/ctl-lua.c b/Controller-afb/ctl-lua.c new file mode 100644 index 0000000..4ef6b65 --- /dev/null +++ b/Controller-afb/ctl-lua.c @@ -0,0 +1,1033 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ref: + * (manual) https://www.lua.org/manual/5.3/manual.html + * (lua->C) http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call + * (lua/C Var) http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/ + * (Lua/C Lib)https://john.nachtimwald.com/2014/07/12/wrapping-a-c-library-in-lua/ + * (Lua/C Table) https://gist.github.com/SONIC3D/10388137 + * (Lua/C Nested table) https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c + * (Lua/C Wrapper) https://stackoverflow.com/questions/45699950/lua-passing-handle-to-function-created-with-newlib + * + */ + +#define _GNU_SOURCE +#include +#include + + +#include "ctl-binding.h" +#include "wrap-json.h" + +#define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg +#define LUA_MSG_MAX_LENGTH 512 +#define JSON_ERROR (json_object*)-1 +static afb_req NULL_AFBREQ = {}; + + +static lua_State* luaState; + +#define CTX_MAGIC 123456789 +#define CTX_TOKEN "AFB_ctx" + +typedef struct { + char *name; + int count; + afb_event event; +} LuaAfbEvent; +static LuaAfbEvent *luaDefaultEvt; + +typedef struct { + int ctxMagic; + afb_req request; + void *handle; + char *info; +} LuaAfbContextT; + +typedef struct { + const char *callback; + json_object *context; + void *handle; +} LuaCallServiceT; + +typedef enum { + AFB_MSG_INFO, + AFB_MSG_WARNING, + AFB_MSG_NOTICE, + AFB_MSG_DEBUG, + AFB_MSG_ERROR, +} LuaAfbMessageT; + +/* + * Note(Fulup): I fail to use luaL_setmetatable and replaced it with a simple opaque + * handle while waiting for someone smarter than me to find a better solution + * https://stackoverflow.com/questions/45596493/lua-using-lua-newuserdata-from-lua-pcall + */ + +STATIC LuaAfbContextT *LuaCtxCheck (lua_State *luaState, int index) { + LuaAfbContextT *afbContext; + //luaL_checktype(luaState, index, LUA_TUSERDATA); + //afbContext = (LuaAfbContextT *)luaL_checkudata(luaState, index, CTX_TOKEN); + luaL_checktype(luaState, index, LUA_TLIGHTUSERDATA); + afbContext = (LuaAfbContextT *) lua_touserdata(luaState, index); + 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, void *handle, const char* info) { + // LuaAfbContextT *afbContext = (LuaAfbContextT *)lua_newuserdata(luaState, sizeof(LuaAfbContextT)); + // luaL_setmetatable(luaState, CTX_TOKEN); + LuaAfbContextT *afbContext = (LuaAfbContextT *)calloc(1, sizeof(LuaAfbContextT)); + lua_pushlightuserdata(luaState, afbContext); + if (!afbContext) { + AFB_ERROR ("LuaCtxPush fail to allocate user data context"); + return NULL; + } + afbContext->ctxMagic=CTX_MAGIC; + afbContext->info=strdup(info); + afbContext->request= request; + afbContext->handle= handle; + return afbContext; +} + +STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { + free(afbContext->info); + free(afbContext); +} + +// Push a json structure on the stack as a LUA table +STATIC int LuaPushArgument (json_object *argsJ) { + + //AFB_NOTICE("LuaPushArgument argsJ=%s", json_object_get_string(argsJ)); + + json_type jtype= json_object_get_type(argsJ); + switch (jtype) { + case json_type_object: { + lua_newtable (luaState); + json_object_object_foreach (argsJ, key, val) { + int done = LuaPushArgument (val); + if (done) { + lua_setfield(luaState,-2, key); + } + } + break; + } + case json_type_array: { + int length= json_object_array_length(argsJ); + lua_newtable (luaState); + for (int idx=0; idx < length; idx ++) { + json_object *val=json_object_array_get_idx(argsJ, idx); + LuaPushArgument (val); + lua_seti (luaState,-2, idx); + } + break; + } + case json_type_int: + lua_pushinteger(luaState, json_object_get_int(argsJ)); + break; + case json_type_string: + lua_pushstring(luaState, json_object_get_string(argsJ)); + break; + case json_type_boolean: + lua_pushboolean(luaState, json_object_get_boolean(argsJ)); + break; + case json_type_double: + lua_pushnumber(luaState, json_object_get_double(argsJ)); + break; + case json_type_null: + AFB_WARNING("LuaPushArgument: NULL object type %s", json_object_get_string(argsJ)); + return 0; + break; + + default: + AFB_ERROR("LuaPushArgument: unsupported Json object type %s", json_object_get_string(argsJ)); + return 0; + } + return 1; +} + +STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx); + +STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { + int idx; + #define LUA_KEY_INDEX -2 + #define LUA_VALUE_INDEX -1 + + json_object *tableJ= json_object_new_object(); + const char *key; + char number[3]; + lua_pushnil(luaState); // 1st key + if (index < 0) index--; + for (idx=1; lua_next(luaState, index) != 0; idx++) { + + // uses 'key' (at index -2) and 'value' (at index -1) + if (lua_type(luaState,LUA_KEY_INDEX) == LUA_TSTRING) key= lua_tostring(luaState, LUA_KEY_INDEX); + else { + snprintf(number, sizeof(number),"%d", idx); + key=number; + } + json_object *argJ= LuaPopOneArg(luaState, LUA_VALUE_INDEX); + json_object_object_add(tableJ, key, argJ); + lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration + } + + // Query is empty free empty json object + if (idx == 1) { + json_object_put(tableJ); + return NULL; + } + return tableJ; +} + +STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx) { + json_object *value=NULL; + + int luaType = lua_type(luaState, idx); + switch(luaType) { + case LUA_TNUMBER: { + lua_Number number= lua_tonumber(luaState, idx);; + int nombre = (int)number; // evil trick to determine wether n fits in an integer. (stolen from ltcl.c) + if (number == nombre) { + value= json_object_new_int((int)number); + } else { + value= json_object_new_double(number); + } + 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: + value= LuaTableToJson(luaState, idx); + break; + case LUA_TNIL: + value=json_object_new_string("nil") ; + break; + case LUA_TUSERDATA: + value=json_object_new_int64((int64_t)lua_touserdata(luaState, idx)); // store userdata as int !!! + break; + + default: + AFB_NOTICE ("LuaPopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); + value=NULL; + } + + return value; +} + +static json_object *LuaPopArgs (lua_State* luaState, int start) { + json_object *responseJ; + + int stop = lua_gettop(luaState); + if(stop-start <0) return NULL; + + // start at 2 because we are using a function array lib + if (start == stop) { + responseJ=LuaPopOneArg (luaState, start); + } else { + // loop on remaining return arguments + responseJ= json_object_new_array(); + for (int idx=start; idx <= stop; idx++) { + json_object *argJ=LuaPopOneArg (luaState, idx); + if (!argJ) goto OnErrorExit; + json_object_array_add(responseJ, argJ); + } + } + + return responseJ; + + OnErrorExit: + return NULL; +} + + +STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { + char *message; + + json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG); + + if (!responseJ) { + luaL_error(luaState,"LuaFormatMessage empty message"); + goto OnErrorExit; + } + + // if we have only on argument just return the value. + if (json_object_get_type(responseJ)!=json_type_array || json_object_array_length(responseJ) <2) { + message= (char*)json_object_get_string(responseJ); + goto PrintMessage; + } + + // extract format and push all other parameter on the stack + message = alloca (LUA_MSG_MAX_LENGTH); + const char *format = json_object_get_string(json_object_array_get_idx(responseJ, 0)); + + int arrayIdx=1; + int targetIdx=0; + + for (int idx=0; format[idx] !='\0'; idx++) { + + if (format[idx]=='%' && format[idx] !='\0') { + json_object *slotJ= json_object_array_get_idx(responseJ, arrayIdx); + //if (slotJ) AFB_NOTICE("**** idx=%d slotJ=%s", arrayIdx, json_object_get_string(slotJ)); + + + switch (format[++idx]) { + case 'd': + if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%d", json_object_get_int(slotJ)); + else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); + arrayIdx++; + break; + case 'f': + if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%f", json_object_get_double(slotJ)); + else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); + arrayIdx++; + break; + + case'%': + message[targetIdx]='%'; + targetIdx++; + break; + + case 's': + default: + if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%s", json_object_get_string(slotJ)); + else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); + arrayIdx++; + } + + } else { + if (targetIdx >= LUA_MSG_MAX_LENGTH) { + AFB_WARNING ("LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH); + targetIdx --; // move backward for EOL + break; + } else { + message[targetIdx++] = format[idx]; + } + } + } + message[targetIdx]='\0'; + +PrintMessage: + switch (action) { + case AFB_MSG_WARNING: + AFB_WARNING (message); + break; + case AFB_MSG_NOTICE: + AFB_NOTICE (message); + break; + case AFB_MSG_DEBUG: + AFB_DEBUG (message); + break; + case AFB_MSG_INFO: + AFB_INFO (message); + break; + case AFB_MSG_ERROR: + default: + AFB_ERROR (message); + } + return 0; // nothing return to lua + + OnErrorExit: // on argument to return (the error message) + return 1; +} + +STATIC int LuaPrintInfo(lua_State* luaState) { + int err=LuaFormatMessage (luaState, AFB_MSG_INFO); + return err; +} + +STATIC int LuaPrintError(lua_State* luaState) { + int err=LuaFormatMessage (luaState, AFB_MSG_ERROR); + return err; // no value return +} + +STATIC int LuaPrintWarning(lua_State* luaState) { + int err=LuaFormatMessage (luaState, AFB_MSG_WARNING); + return err; +} + +STATIC int LuaPrintNotice(lua_State* luaState) { + int err=LuaFormatMessage (luaState, AFB_MSG_NOTICE); + return err; +} + +STATIC int LuaPrintDebug(lua_State* luaState) { + int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG); + return err; +} + +STATIC int LuaAfbSuccess(lua_State* luaState) { + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) goto OnErrorExit; + + // ignore context argument + json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + if (responseJ == JSON_ERROR) return 1; + + afb_req_success(afbContext->request, responseJ, NULL); + + LuaCtxFree(afbContext); + return 0; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbFail(lua_State* luaState) { + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) goto OnErrorExit; + + json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + if (responseJ == JSON_ERROR) return 1; + + afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(responseJ)); + + 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; + int count=1; + + lua_getglobal(luaState, contextCB->callback); + + // push error status & response + lua_pushboolean(luaState, iserror); + count+= LuaPushArgument(responseJ); + count+= LuaPushArgument(contextCB->context); + + int err=lua_pcall(luaState, count, LUA_MULTRET, 0); + if (err) { + AFB_ERROR ("LUA-SERICE-CB:FAIL response=%s err=%s", json_object_get_string(responseJ), lua_tostring(luaState,-1) ); + } + + free (contextCB); +} + + +STATIC int LuaAfbService(lua_State* luaState) { + int count = lua_gettop(luaState); + + // note: argument start at 2 because of AFB: table + 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; + } + + // get api/verb+query + const char *api = lua_tostring(luaState,2); + const char *verb= lua_tostring(luaState,3); + json_object *queryJ= LuaTableToJson(luaState, 4); + if (queryJ == JSON_ERROR) return 1; + + LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); + contextCB->callback= lua_tostring(luaState, 5); + contextCB->context = LuaPopArgs(luaState, 6); + + afb_service_call(api, verb, queryJ, LuaAfbServiceCB, contextCB); + + return 0; // no value return + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbServiceSync(lua_State* luaState) { + int count = lua_gettop(luaState); + json_object *responseJ; + + // note: argument start at 2 because of AFB: table + if (count <3 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4)) { + lua_pushliteral (luaState, "LuaAfbServiceSync-Syntax is error,data=AFB:service_call (api, verb, query)"); + goto OnErrorExit; + } + + // get api/verb+query + const char *api = lua_tostring(luaState,2); + const char *verb= lua_tostring(luaState,3); + json_object *queryJ= LuaTableToJson(luaState, 4); + + int iserror=afb_service_call_sync (api, verb, queryJ, &responseJ); + + // push error status & response + count=1; lua_pushboolean(luaState, iserror); + count+= LuaPushArgument(responseJ); + + return count; // return count values + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbEventPush(lua_State* luaState) { + LuaAfbEvent *afbevt; + int index; + + // if no private event handle then use default binding event + if (lua_islightuserdata(luaState, LUA_FIST_ARG)) { + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG); + index=LUA_FIST_ARG+1; + } else { + index=LUA_FIST_ARG; + afbevt=luaDefaultEvt; + } + + if (!afb_event_is_valid(afbevt->event)) { + lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event"); + goto OnErrorExit; + } + + json_object *ctlEventJ= LuaTableToJson(luaState, index); + if (!ctlEventJ) { + lua_pushliteral (luaState, "LuaAfbEventPush-Syntax is AFB:signal ([evtHandle], {lua table})"); + goto OnErrorExit; + } + + int done = afb_event_push(afbevt->event, ctlEventJ); + if (!done) { + lua_pushliteral (luaState, "LuaAfbEventPush-Fail No Subscriber to event"); + AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); + goto OnErrorExit; + } + afbevt->count++; + return 0; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbEventSubscribe(lua_State* luaState) { + LuaAfbEvent *afbevt; + + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) { + lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail Invalid request handle"); + goto OnErrorExit; + } + + // if no private event handle then use default binding event + if (lua_islightuserdata(luaState, LUA_FIST_ARG+1)) { + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG+1); + } else { + afbevt=luaDefaultEvt; + } + + if (!afb_event_is_valid(afbevt->event)) { + lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event handle"); + goto OnErrorExit; + } + + int err = afb_req_subscribe(afbContext->request, afbevt->event); + if (err) { + lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail No Subscriber to event"); + AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); + goto OnErrorExit; + } + afbevt->count++; + return 0; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbEventMake(lua_State* luaState) { + int count = lua_gettop(luaState); + LuaAfbEvent *afbevt=calloc(1,sizeof(LuaAfbEvent)); + + if (count != LUA_FIST_ARG || !lua_isstring(luaState, LUA_FIST_ARG)) { + lua_pushliteral (luaState, "LuaAfbEventMake-Syntax is evtHandle= AFB:event ('myEventName')"); + goto OnErrorExit; + } + + // event name should be the only argument + afbevt->name= strdup (lua_tostring(luaState,LUA_FIST_ARG)); + + // create a new binder event + afbevt->event = afb_daemon_make_event(afbevt->name); + if (!afb_event_is_valid(afbevt->event)) { + lua_pushliteral (luaState, "LuaAfbEventMake-Fail to Create Binder event"); + goto OnErrorExit; + } + + // push event handler as a LUA opaque handle + lua_pushlightuserdata(luaState, afbevt); + return 1; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +// Function call from LUA when lua2c plugin L2C is used +PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context) { + + json_object *argsJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + int response = (*callback) (funcname, argsJ, context); + + // push response to LUA + lua_pushinteger(luaState, response); + return 1; +} + +// Generated some fake event based on watchdog/counter +PUBLIC int LuaCallFunc (DispatchSourceT source, DispatchActionT *action, json_object *queryJ) { + + int err, count; + + json_object* argsJ = action->argsJ; + const char* func = action->call; + + // load function (should exist in CONTROL_PATH_LUA + lua_getglobal(luaState, func); + + // push source on the stack + count=1; + lua_pushinteger(luaState, source); + + // push argsJ on the stack + if (!argsJ) { + lua_pushnil(luaState); + count++; + } else { + count+= LuaPushArgument (argsJ); + } + + // push queryJ on the stack + if (!queryJ) { + lua_pushnil(luaState); + count++; + } else { + count+= LuaPushArgument (queryJ); + } + + // effectively exec LUA script code + err=lua_pcall(luaState, count, 1, 0); + if (err) { + AFB_ERROR("LuaCallFunc Fail calling %s error=%s", func, lua_tostring(luaState,-1)); + goto OnErrorExit; + } + + // return LUA script value + int rc= (int)lua_tointeger(luaState, -1); + return rc; + + OnErrorExit: + return -1; +} + + +// Execute LUA code from received API request +STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { + + int err, count=0; + + json_object* queryJ = afb_req_json(request); + + switch (action) { + + case LUA_DOSTRING: { + const char *script = json_object_get_string(queryJ); + err=luaL_loadstring(luaState, script); + if (err) { + 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,NULL,script); + if (!afbContext) goto OnErrorExit; + + break; + } + + case LUA_DOCALL: { + const char *func; + json_object *argsJ=NULL; + + err= wrap_json_unpack (queryJ, "{s:s, s?o !}", "func", &func, "args", &argsJ); + if (err) { + AFB_ERROR ("LUA-DOCALL-SYNTAX missing func|args query=%s", json_object_get_string(queryJ)); + goto OnErrorExit; + } + + // load function (should exist in CONTROL_PATH_LUA + lua_getglobal(luaState, func); + + // Push AFB client context on the stack + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); + if (!afbContext) goto OnErrorExit; + + // push query on the stack + if (!argsJ) { + lua_pushnil(luaState); + count++; + } else { + count+= LuaPushArgument (argsJ); + } + + break; + } + + case LUA_DOSCRIPT: { // Fulup need to fix argument passing + const char *script; + char*func=NULL; + char *filename; char*fullpath; + char luaScriptPath[CONTROL_MAXPATH_LEN]; + json_object *argsJ=NULL; + int index; + + // scan luascript search path once + static json_object *luaScriptPathJ =NULL; + + err= wrap_json_unpack (queryJ, "{s:s, s?s s?o !}", "script", &script,"func", &func, "args", &argsJ); + if (err) { + AFB_ERROR ("LUA-DOSCRIPT-SYNTAX:missing script|(args,arg) query=%s", json_object_get_string(queryJ)); + goto OnErrorExit; + } + + // search for filename=script in CONTROL_LUA_PATH + if (!luaScriptPathJ) luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE,CONTROL_DOSCRIPT_PRE "-", script); + for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { + json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); + + err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); + if (err) { + AFB_ERROR ("LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ)); + goto OnErrorExit; + } + + if (index > 0) AFB_WARNING("LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); + else { + strncpy (luaScriptPath, fullpath, sizeof(luaScriptPath)); + strncat (luaScriptPath, "/", sizeof(luaScriptPath)); + strncat (luaScriptPath, filename, sizeof(luaScriptPath)); + } + } + + err= luaL_loadfile(luaState, luaScriptPath); + if (err) { + AFB_ERROR ("LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); + goto OnErrorExit; + } + + // script was loaded we need to parse to make it executable + err=lua_pcall(luaState, 0, 0, 0); + if (err) { + AFB_ERROR ("LUA-DOSCRIPT:FAIL to load %s", luaScriptPath); + goto OnErrorExit; + } + + // if no func name given try to deduct from filename + if (!func) func= (char*)GetMidleName(filename); + if (!func) { + AFB_ERROR ("LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); + goto OnErrorExit; + } + + // load function (should exist in CONTROL_PATH_LUA + lua_getglobal(luaState, func); + + // Push AFB client context on the stack + LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); + if (!afbContext) goto OnErrorExit; + + // push function arguments + if (!argsJ) { + lua_pushnil(luaState); + count++; + } else { + count+= LuaPushArgument(argsJ); + } + + break; + } + + default: + AFB_ERROR ("LUA-DOSCRIPT-ACTION unknown query=%s", json_object_get_string(queryJ)); + goto OnErrorExit; + } + + // effectively exec LUA code (afb_reply/fail done later from callback) + err=lua_pcall(luaState, count+1, 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; + } + return; + + OnErrorExit: + afb_req_fail(request,"LUA:ERROR", lua_tostring(luaState,-1)); + return; +} + +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 int LuaTimerClear (lua_State* luaState) { + + // Get Timer Handle + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) goto OnErrorExit; + + // retrieve useful information opaque handle + TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; + + AFB_NOTICE ("LuaTimerClear timer=%s", timerHandle->label); + TimerEvtStop(timerHandle); + + return 0; //happy end + +OnErrorExit: + return 1; +} +STATIC int LuaTimerGet (lua_State* luaState) { + + // Get Timer Handle + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); + if (!afbContext) goto OnErrorExit; + + // retrieve useful information opaque handle + TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; + + // create response as a JSON object + json_object *responseJ= json_object_new_object(); + json_object_object_add(responseJ,"label", json_object_new_string(timerHandle->label)); + json_object_object_add(responseJ,"delay", json_object_new_int(timerHandle->delay)); + json_object_object_add(responseJ,"count", json_object_new_int(timerHandle->count)); + + // return JSON object as Lua table + int count=LuaPushArgument(responseJ); + + // free json object + json_object_put(responseJ); + + return count; // return argument + +OnErrorExit: + return 0; +} + +// Timer Callback + +// Set timer +STATIC int LuaTimerSetCB (void *handle) { + LuaCallServiceT *contextCB =(LuaCallServiceT*) handle; + TimerHandleT *timerHandle = (TimerHandleT*) contextCB->handle; + int count; + + // push timer handle and user context on Lua stack + lua_getglobal(luaState, contextCB->callback); + + // Push timer handle + LuaAfbContextT *afbContext= LuaCtxPush(luaState, NULL_AFBREQ, contextCB->handle, timerHandle->label); + if (!afbContext) goto OnErrorExit; + count=1; + + // Push user Context + count+= LuaPushArgument(contextCB->context); + + int err=lua_pcall(luaState, count, LUA_MULTRET, 0); + if (err) { + AFB_ERROR ("LUA-TIMER-CB:FAIL response=%s err=%s", json_object_get_string(contextCB->context), lua_tostring(luaState,-1)); + goto OnErrorExit; + } + + // get return parameter + if (!lua_isboolean(luaState, -1)) { + return (lua_toboolean(luaState, -1)); + } + + // timer last run free context resource + if (timerHandle->count == 1) { + LuaCtxFree(afbContext); + } + return 0; // By default we are happy + + OnErrorExit: + return 1; // stop timer +} + +STATIC int LuaTimerSet(lua_State* luaState) { + const char *label=NULL, *info=NULL; + int delay=0, count=0; + + json_object *timerJ = LuaPopOneArg(luaState, LUA_FIST_ARG); + const char *callback = lua_tostring(luaState, LUA_FIST_ARG + 1); + json_object *contextJ = LuaPopOneArg(luaState, LUA_FIST_ARG + 2); + + if (lua_gettop(luaState) != LUA_FIST_ARG+2 || !timerJ || !callback || !contextJ) { + lua_pushliteral(luaState, "LuaTimerSet-Syntax timerset (timerT, 'callback', contextT)"); + goto OnErrorExit; + } + + int err = wrap_json_unpack(timerJ, "{ss, s?s si, si !}", "label", &label, "info", &info, "delay", &delay, "count", &count); + if (err) { + lua_pushliteral(luaState, "LuaTimerSet-Syntax timerT={label:xxx delay:ms, count:xx}"); + goto OnErrorExit; + } + + // everything look fine create timer structure + TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); + timerHandle->delay=delay; + timerHandle->count=count; + timerHandle->label=label; + + // Allocate handle to store context and callback + LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); + contextCB->callback= callback; + contextCB->context = contextJ; + contextCB->handle = timerHandle; + + // fire timer + TimerEvtStart (timerHandle, LuaTimerSetCB, contextCB); + + return 0; // Happy No Return Function + +OnErrorExit: + lua_error(luaState); + return 1; // return error code +} + +// Register a new L2c list of LUA user plugin commands +PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count) { + // luaL_newlib(luaState, l2cFunc); macro does not work with pointer :( + luaL_checkversion(luaState); + lua_createtable(luaState, 0, count+1); + luaL_setfuncs(luaState,l2cFunc,0); + lua_setglobal(luaState, label); +} + +static const luaL_Reg afbFunction[] = { + {"timerclear", LuaTimerClear}, + {"timerget" , LuaTimerGet}, + {"timerset" , LuaTimerSet}, + {"notice" , LuaPrintNotice}, + {"info" , LuaPrintInfo}, + {"warning" , LuaPrintWarning}, + {"debug" , LuaPrintDebug}, + {"error" , LuaPrintError}, + {"servsync" , LuaAfbServiceSync}, + {"service" , LuaAfbService}, + {"success" , LuaAfbSuccess}, + {"fail" , LuaAfbFail}, + {"subscribe" , LuaAfbEventSubscribe}, + {"evtmake" , LuaAfbEventMake}, + {"evtpush" , LuaAfbEventPush}, + + {NULL, NULL} /* sentinel */ +}; + +// Create Binding Event at Init +PUBLIC int LuaLibInit () { + int err, index; + + // search for default policy config file + char fullprefix[CONTROL_MAXPATH_LEN]; + strncpy (fullprefix, CONTROL_CONFIG_PRE "-", sizeof(fullprefix)); + strncat (fullprefix, GetBinderName(), sizeof(fullprefix)); + strncat (fullprefix, "-", sizeof(fullprefix)); + + json_object *luaScriptPathJ = ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, fullprefix, "lua"); + + // open a new LUA interpretor + luaState = luaL_newstate(); + if (!luaState) { + AFB_ERROR ("LUA_INIT: Fail to open lua interpretor"); + goto OnErrorExit; + } + + // load auxiliary libraries + luaL_openlibs(luaState); + + // redirect print to AFB_NOTICE + luaL_newlib(luaState, afbFunction); + lua_setglobal(luaState, "AFB"); + + // create default lua event to send test pause/resume + luaDefaultEvt=calloc(1,sizeof(LuaAfbEvent)); + luaDefaultEvt->name=CONTROL_LUA_EVENT; + luaDefaultEvt->event = afb_daemon_make_event(CONTROL_LUA_EVENT); + if (!afb_event_is_valid(luaDefaultEvt->event)) { + AFB_ERROR ("POLCTL_INIT: Cannot register lua-events=%s ", CONTROL_LUA_EVENT); + goto OnErrorExit;; + } + + // load+exec any file found in LUA search path + for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { + json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); + + char *filename; char*fullpath; + err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); + if (err) { + AFB_ERROR ("LUA-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ)); + goto OnErrorExit; + } + + char filepath[CONTROL_MAXPATH_LEN]; + strncpy(filepath, fullpath, sizeof(filepath)); + strncat(filepath, "/", sizeof(filepath)); + strncat(filepath, filename, sizeof(filepath)); + err= luaL_loadfile(luaState, filepath); + if (err) { + AFB_ERROR ("LUA-LOAD HOOPs Error in LUA loading scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); + goto OnErrorExit; + } + + // exec/compil script + err = lua_pcall(luaState, 0, 0, 0); + if (err) { + AFB_ERROR ("LUA-LOAD HOOPs Error in LUA exec scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); + goto OnErrorExit; + } + } + + // no policy config found remove control API from binder + if (index == 0) { + AFB_WARNING ("POLICY-INIT:WARNING No Control LUA file in path=[%s]", CONTROL_LUA_PATH); + } + + AFB_DEBUG ("Audio control-LUA Init Done"); + return 0; + + OnErrorExit: + return 1; +} + \ No newline at end of file diff --git a/Controller-afb/ctl-plugin-sample.c b/Controller-afb/ctl-plugin-sample.c new file mode 100644 index 0000000..1d66802 --- /dev/null +++ b/Controller-afb/ctl-plugin-sample.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Sample plugin for Controller + */ + + +#define _GNU_SOURCE +#include +#include + +#include "ctl-binding.h" + +#define MY_PLUGIN_MAGIC 987654321 + +typedef struct { + int magic; + int count; +} MyPluginCtxT; + +STATIC const char* jsonToString (json_object *valueJ) { + const char *value; + if (valueJ) + value=json_object_get_string(valueJ); + else + value="NULL"; + + return value; +} + +// Declare this sharelib as a Controller Plugin +CTLP_REGISTER("MyCtlSamplePlugin"); + +// Call at initialisation time +PUBLIC CTLP_ONLOAD(label, version, info) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)calloc (1, sizeof(MyPluginCtxT)); + pluginCtx->magic = MY_PLUGIN_MAGIC; + pluginCtx->count = -1; + + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:Onload label=%s version=%s info=%s", label, info, version); + return (void*)pluginCtx; +} + +PUBLIC CTLP_CAPI (SamplePolicyInit, source, label, argsJ, queryJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLLER-PLUGIN-SAMPLE:SamplePolicyInit (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + + pluginCtx->count = 0; + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:Init label=%s args=%s\n", label, jsonToString(argsJ)); + return 0; +} + +PUBLIC CTLP_CAPI (sampleControlMultimedia, source, label, argsJ,queryJ,context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLLER-PLUGIN-SAMPLE:sampleControlMultimedia (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d" + , label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); + return 0; +} + +PUBLIC CTLP_CAPI (sampleControlNavigation, source, label, argsJ, queryJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLLER-PLUGIN-SAMPLE:sampleControlNavigation (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:sampleControlNavigation SamplePolicyCount action=%s args=%s query=%s count=%d" + ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); + return 0; +} + +PUBLIC CTLP_CAPI (SampleControlEvent, source, label, argsJ, queryJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLLER-PLUGIN-SAMPLE:cousampleControlMultimediant (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d" + ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count); + return 0; +} + +// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file +PUBLIC CTLP_LUA2C (Lua2cHelloWorld1, label, argsJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 SamplePolicyCount action=%s args=%s count=%d" + ,label, jsonToString(argsJ), pluginCtx->count); + return 0; +} + +// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file +PUBLIC CTLP_LUA2C (Lua2cHelloWorld2, label, argsJ, context) { + MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context; + + if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) { + AFB_ERROR("CONTROLLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 (Hoops) Invalid Sample Plugin Context"); + return -1; + }; + pluginCtx->count++; + AFB_NOTICE ("CONTROLLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 SamplePolicyCount action=%s args=%s count=%d" + ,label, jsonToString(argsJ), pluginCtx->count); + return 0; +} diff --git a/Controller-afb/ctl-policy.c b/Controller-afb/ctl-policy.c new file mode 100644 index 0000000..e9798b3 --- /dev/null +++ b/Controller-afb/ctl-policy.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, something express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "wrap-json.h" +#include "ctl-binding.h" + +STATIC PolicyCtlConfigT *ctlHandle = NULL; + +// List Avaliable Configuration Files +STATIC json_object* ScanForConfig (char* searchPath) { + json_object *responseJ; + DIR *dirHandle; + char *dirPath; + char* dirList= strdup(searchPath); + + responseJ = json_object_new_array(); + for (dirPath= strtok(dirList, ":"); dirPath && *dirPath; dirPath=strtok(NULL,":")) { + struct dirent *dirEnt; + + dirHandle = opendir (dirPath); + if (!dirHandle) { + AFB_NOTICE ("CONFIG-SCANNING dir=%s not readable", dirPath); + continue; + } + + AFB_NOTICE ("CONFIG-SCANNING:ctl_listconfig scanning: %s", dirPath); + while ((dirEnt = readdir(dirHandle)) != NULL) { + // Unknown type is accepted to support dump filesystems + if (dirEnt->d_type == DT_REG || dirEnt->d_type == DT_UNKNOWN) { + struct json_object *pathJ = json_object_new_object(); + json_object_object_add(pathJ, "dirpath", json_object_new_string(dirPath)); + json_object_object_add(pathJ, "filename", json_object_new_string(dirEnt->d_name)); + json_object_array_add(responseJ, pathJ); + } + } + } + + free (dirList); + return (responseJ); +} + +PUBLIC void ctlapi_authorize (PolicyCtlEnumT control, afb_req request) { + json_object*tmpJ; + + json_object* queryJ= afb_req_json(request); + int done=json_object_object_get_ex(queryJ, "closing", &tmpJ); + if (done) return; + +} + + +// List Avaliable Configuration Files +PUBLIC void ctlapi_config (struct afb_req request) { + json_object*tmpJ; + char *dirList; + + json_object* queryJ = afb_req_json(request); + if (queryJ && json_object_object_get_ex (queryJ, "cfgpath" , &tmpJ)) { + dirList = strdup (json_object_get_string(tmpJ)); + } else { + dirList = strdup (CONTROL_CONFIG_PATH); + AFB_NOTICE ("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH); + } + + // get list of config file + struct json_object *responseJ = ScanForConfig(dirList); + + if (json_object_array_length(responseJ) == 0) { + afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH"); + } else { + afb_req_success(request, responseJ, NULL); + } + + return; +} + +STATIC PolicyActionT **PolicyLoadActions (json_object *actionsJ) { + int err; + PolicyActionT ** actions; + + // unpack individual action object + int actionUnpack (json_object *actionJ, PolicyActionT *action) { + + err= wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s !}" + , "label",&action->label, "info",&action->info, "callback",&action->callback, "query",&queryJ, "api",&action->api, "verb", &action->verb); + if (err) { + AFB_ERROR ("POLICY-LOAD-ACTION Missing something label|info|callback|api|verb|query in %s", json_object_get_string(actionJ)); + return -1; + } + if (!action->callback || !(action->api && action->verb)) { + AFB_ERROR ("POLICY-LOAD-ACTION Missing something callback|(api+verb) in %s", json_object_get_string(actionJ)); + return -1; + } + return 0; + }; + + // action array is close with a nullvalue; + if (json_object_get_type(actionsJ) == json_type_array) { + int count = json_object_array_length(actionsJ); + actions = calloc (count+1, sizeof(PolicyActionT)); + + for (int idx=0; idx < count; idx++) { + json_object *actionJ = json_object_array_get_idx(actionsJ, idx); + err = actionUnpack (actionJ, &actions[idx]); + if (err) goto OnErrorExit; + } + + } else { + actions = calloc (2, sizeof(PolicyActionT)); + err = actionUnpack (actionsJ, &actions[0]); + if (err) goto OnErrorExit; + } + + return actions; + + OnErrorExit: + return NULL; + +} + +// load control policy from file using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values +STATIC PolicyCtlConfigT *PolicyLoadConfig (const char* filepath) { + json_object *policyConfigJ, *ignoreJ, *actionsJ; + PolicyCtlConfigT *policyConfig = calloc (1, sizeof(PolicyCtlConfigT)); + int err; + + // Load JSON file + policyConfigJ= json_object_from_file(filepath); + if (!policyConfigJ) goto OnErrorExit; + + json_object *metadataJ, *onloadJ, *controlsJ, *eventsJ; + err= wrap_json_unpack(policyConfigJ, "{s?o,so,s?o,so,so !}", "$schema", &ignoreJ, "metadata",&metadataJ, "onload",&onloadJ, "controls",&controlsJ, "events",&eventsJ); + if (err) { + AFB_ERROR ("POLICY-LOAD-ERRROR Missing something metadata|onload|controls|events in %s", json_object_get_string(policyConfigJ)); + goto OnErrorExit; + } + + PolicyHandleT *policyHandle = calloc (1, sizeof(PolicyHandleT)); + err= wrap_json_unpack(metadataJ, "{so,s?s,s?s !}", "label", &policyHandle->label, "info",&policyHandle->info, "version",&policyHandle->version); + if (err) { + AFB_ERROR ("POLICY-LOAD-CONFIG Missing something label|info|version in %s", json_object_get_string(metadataJ)); + goto OnErrorExit; + } + + if (onloadJ) { + err= wrap_json_unpack(onloadJ, "{s?o,s?s,s?s !}", "info",&ignoreJ, "label",&ignoreJ, "actions",&actionsJ); + if (err) { + AFB_ERROR ("POLICY-LOAD-CONFIG Missing something label|info|plugin|actions in %s", json_object_get_string(metadataJ)); + goto OnErrorExit; + } + policyConfig->onload = PolicyLoadActions (actionsJ); + } + + return policyControl; + +OnErrorExit: + return NULL; +} + +// Load default config file at init +PUBLIC int PolicyInit () { + int index, err; + + + // search for default policy config file + json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH); + + for (index=0; index < json_object_array_length(responseJ); index++) { + json_object *entryJ=json_object_array_get_idx(responseJ, index); + + char *filename; char*dirpath; + err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "dirpath", &dirpath,"filename", &filename); + if (err) { + AFB_ERROR ("POLICY-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ)); + goto OnErrorExit; + } + + if (strcasestr(filename, CONTROL_CONFIG_FILE)) { + char filepath[255]; + strncpy(filepath, dirpath, sizeof(filepath)); + strncat(filepath, "/", sizeof(filepath)); + strncat(filepath, filename, sizeof(filepath)); + ctlHandle = PolicyLoadConfig (filepath); + if (!ctlHandle) goto OnErrorExit; + break; + } + } + + // no policy config found remove control API from binder + if (index == 0) goto OnErrorExit; + + AFB_NOTICE ("SUCCES: Audio Control Policy Init"); + return 0; + +OnErrorExit: + AFB_NOTICE ("ERROR: Audio Control Policy Init"); + return 1; +} + + + diff --git a/Controller-afb/ctl-timer.c b/Controller-afb/ctl-timer.c new file mode 100644 index 0000000..a826f9f --- /dev/null +++ b/Controller-afb/ctl-timer.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "ctl-binding.h" + +#define DEFAULT_PAUSE_DELAY 3000 +#define DEFAULT_TEST_COUNT 1 +typedef struct { + int value; + const char *label; +} AutoTestCtxT; + +static afb_event afbevt; + +STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { + TimerHandleT *timerHandle = (TimerHandleT*) handle; + int done; + uint64_t usec; + + // Rearm timer if needed + timerHandle->count --; + if (timerHandle->count == 0) { + sd_event_source_unref(source); + free (handle); + return 0; + } + else { + // otherwise validate timer for a new run + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); + sd_event_source_set_time(source, usec + timerHandle->delay*1000); + } + + done= timerHandle->callback(timerHandle->context); + if (!done) goto OnErrorExit; + + return 0; + +OnErrorExit: + AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->label); + return -1; +} + +PUBLIC void TimerEvtStop(TimerHandleT *timerHandle) { + + sd_event_source_unref(timerHandle->evtSource); + free (timerHandle); +} + + +PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context) { + uint64_t usec; + + // populate CB handle + timerHandle->callback=callback; + timerHandle->context=context; + + // set a timer with ~250us accuracy + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay*1000, 250, TimerNext, timerHandle); +} + +PUBLIC afb_event TimerEvtGet(void) { + return afbevt; +} + + +// Create Binding Event at Init +PUBLIC int TimerEvtInit () { + + // create binder event to send test pause/resume + afbevt = afb_daemon_make_event("control"); + if (!afb_event_is_valid(afbevt)) { + AFB_ERROR ("POLCTL_INIT: Cannot register ctl-events"); + return 1; + } + + AFB_DEBUG ("Audio Control-Events Init Done"); + return 0; +} + diff --git a/HAL-afb/HAL-interface/hal-interface.c b/HAL-afb/HAL-interface/hal-interface.c index 4d86504..0abe67e 100644 --- a/HAL-afb/HAL-interface/hal-interface.c +++ b/HAL-afb/HAL-interface/hal-interface.c @@ -44,7 +44,7 @@ STATIC int halCtlStringToIndex(const char* label) { alsaHalMapT *halCtls = halSndCard->ctls; for (int idx = 0; halCtls[idx].tag != EndHalCrlTag; idx++) { - if (halCtls[idx].label && !strcmp(halCtls[idx].label, label)) return idx; + if (halCtls[idx].label && !strcasecmp(halCtls[idx].label, label)) return idx; } // not found @@ -502,11 +502,12 @@ PUBLIC int halServiceInit(const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard json_object *ctlJ; // Try to find best equivalent label for tag - if (halCtls[idx].tag >StartHalCrlTag && halCtls[idx].tag < EndHalCrlTag && halCtls[idx].label != NULL) { + if (halCtls[idx].tag >StartHalCrlTag && halCtls[idx].tag < EndHalCrlTag && halCtlsLabels[halCtls[idx].tag] != NULL) { halCtls[idx].label = halCtlsLabels[halCtls[idx].tag]; } else { if (halCtls[idx].ctl.name) halCtls[idx].label=halCtls[idx].ctl.name; else if (halCtls[idx].info) halCtls[idx].label=halCtls[idx].info; + else halCtls[idx].label="NoHalCttNameSet"; } ctlJ = json_object_new_object(); @@ -617,9 +618,9 @@ PUBLIC void halServiceEvent(const char *evtname, json_object *eventJ) { PUBLIC afb_verb_v2 halServiceApi[] = { /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ { .verb = "ping", .callback = pingtest, .info = "ping test for API"}, - { .verb = "ctl-list", .callback = halListCtls, .info = "List AGL normalised Sound Controls"}, - { .verb = "ctl-get", .callback = halGetCtls, .info = "Get one/many sound controls"}, - { .verb = "ctl-set", .callback = halSetCtls, .info = "Set one/many sound controls"}, - { .verb = "evt-sub", .callback = halSubscribe, .info = "Subscribe to HAL events"}, + { .verb = "ctllist", .callback = halListCtls, .info = "List AGL normalised Sound Controls"}, + { .verb = "ctlget", .callback = halGetCtls, .info = "Get one/many sound controls"}, + { .verb = "ctlset", .callback = halSetCtls, .info = "Set one/many sound controls"}, + { .verb = "evtsub", .callback = halSubscribe, .info = "Subscribe to HAL events"}, { .verb = NULL} /* marker for end of the array */ }; diff --git a/conf.d/alsa-sample/asoundrc.sample b/conf.d/alsa-sample/asoundrc.sample deleted file mode 100644 index 1786c46..0000000 --- a/conf.d/alsa-sample/asoundrc.sample +++ /dev/null @@ -1,160 +0,0 @@ -# -# Author: Fulup Ar Foll -# Object: PCM hook type -# -# Test : Note: Jabra_USB=hw:v1340 -# Check SoundCard speaker-test -Dhw:v1340 -c2 -twav -# Check MixerPCM speaker-test -DMyMixerPCM -c2 -twav -# Check HookPCM speaker-test -DMyNavigationHook -c2 -twav -# Check NavPCM speaker-test -DMyNavPCM -c2 -twav -# MultiMedia aplay -DDMyNavPCM /usr/share/sounds/alsa/test.wav -# -# Bug/Feature: when softvol control is initialised from plugin and not -# from AGL binding. At 1st run ctl has invalid TLV and cannot be -# use. Bypass Solution: -# * start audio-binder before playing sound (binding create control before softvol plugin) -# * run a dummy aplay -DMyNavPCM "" to get a clean control -# -# References: https://www.spinics.net/lists/alsa-devel/msg54235.html -# -------------------------------------------------------------------- - -# Mixer PCM allow to play multiple stream simultaneously -# ------------------------------------------------------ -pcm.MyMixerPCM { - type dmix - ipc_key 1024 - ipc_key_add_uid false - ipc_perm 0666 # mixing for all users - - # Define target effective sound card (cannot be a plugin) - slave { - pcm "hw:v1340" #Jabra Solmate - period_time 0 - period_size 1024 - buffer_size 8192 - rate 44100 - } - - # DMIX can only map two channels - bindings { - 0 0 - 1 1 - } -} - -# Define a Hook_type with a private sharelib -# ------------------------------------------- -pcm_hook_type.MyHookPlugin { - install "AlsaInstallHook" - lib "/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build/Alsa-Plugin/Alsa-Policy-Hook/policy_hook_cb.so" -} - -# Define a HookedPCM that point to Hook_type sharelib -# ---------------------------------------------------- -pcm.MyNavigationHook { - type hooks - slave.pcm "MyMixerPCM" - - # Defined used hook sharelib and provide arguments/config to install func - hooks.0 { - type "MyHookPlugin" - hook_args { - verbose true # print few log messages (default false); - - # Every Call should return OK in order PCM to open (default timeout 100ms) - uri "ws://localhost:1234/api?token='audio-agent-token'" - request { - # Request autorisation to write on navigation - RequestNavigation { - api "polctl" - verb "navigation" - } - # subscribe to Audio Agent Event - SubscriveEvents { - api "polctl" - verb "monitor" - } - TestAutoStop { - api "polctl" - verb "event_test" - query "{'label':'stop', 'delay':10000}" - } - TestAutoStart { - api "polctl" - verb "event_test" - query "{'label':'stop', 'delay':20000}" - } - # start a test pause/resume not supported by every hardware - TestPauseResume { - api "polctl" - verb "event_test" - query "{'label':'pause', 'delay':3000, 'count':10}" - } - } - } - } -} - -# If hardware does not support mixer emulate it with softvol -# ----------------------------------------------------------- -pcm.MyMultimediaPCM { - type softvol - - # Point Slave on HOOK for policies control - slave.pcm "MyNavigationHook" - - # resolution=HAL(valMax+1) (default=256) - resolution 256 - - # name should match with HAL but do not set card=xx - control.name "Playback Navigation" - - # Make this plugin visible from aplay -L - hint { - show on - description "Navigation SolftVol PCM" - } -} - -# If hardware does not support mixer emulate it with softvol -# ----------------------------------------------------------- -pcm.MyNavPCM { - type softvol - - # Point Slave on HOOK for policies control - slave.pcm "MyNavigationHook" - - # resolution=HAL(valMax+1) (default=256) - resolution 256 - - # name should match with HAL but do not set card=xx - control.name "Playback Navigation" - - # Make this plugin visible from aplay -L - hint { - show on - description "Navigation SolftVol PCM" - } -} - -# If hardware does not support mixer emulate it with softvol -# ----------------------------------------------------------- -pcm.MyAlarmPCM { - type softvol - - # Point Slave on HOOK for policies control - slave.pcm "MyNavigationHook" - - # resolution=HAL(valMax+1) (default=256) - resolution 256 - - # name should match with HAL but do not set card=xx - control.name "Playback Navigation" - - # Make this plugin visible from aplay -L - hint { - show on - description "Navigation SolftVol PCM" - } -} - diff --git a/conf.d/alsa-sample/ucm.sample/HDA Intel PCH.conf b/conf.d/alsa-sample/ucm.sample/HDA Intel PCH.conf deleted file mode 100644 index f6608a0..0000000 --- a/conf.d/alsa-sample/ucm.sample/HDA Intel PCH.conf +++ /dev/null @@ -1,6 +0,0 @@ -Comment "Leon internal card" - -SectionUseCase."HiFi" { - File "HiFi.conf" - Comment "Default" -} diff --git a/conf.d/alsa-sample/ucm.sample/HiFi.conf b/conf.d/alsa-sample/ucm.sample/HiFi.conf deleted file mode 100644 index 9a53c8c..0000000 --- a/conf.d/alsa-sample/ucm.sample/HiFi.conf +++ /dev/null @@ -1,84 +0,0 @@ -SectionVerb { - EnableSequence [ - cdev "hw:PCH" - - cset "name='Master Playback Switch' on" - cset "name='Headphone Playback Switch' off" - cset "name='Speaker Playback Switch' on" - - cset "name='Capture Switch' on" - cset "name='Capture Volume' 39" - cset "name='Mic Boost Volume' 2" - cset "name='Internal Mic Boost Volume' 0" - #cset "name='Capture Source' 0" - ] - DisableSequence [ - ] - Value { - TQ "Music" - OutputDspName "speaker_eq" - PlaybackPCM "hw:PCH,0" - } -} - -SectionDevice."Headphone".0 { - Value { - JackName "Headphone Jack" - OutputDspName "Jheadphone" - } - EnableSequence [ - cdev "hw:PCH" - - cset "name='Speaker Playback Switch' off" - cset "name='Headphone Playback Switch' on" - ] - DisableSequence [ - cdev "hw:PCH" - - cset "name='Headphone Playback Switch' off" - cset "name='Speaker Playback Switch' on" - ] -} - -SectionDevice."Mic".0 { - Value { - JackName "Mic Jack" - } - EnableSequence [ - cdev "hw:PCH" - - #cset "name='Capture Source' 1" - ] - DisableSequence [ - cdev "hw:PCH" - - cset "name='Capture Source' 0" - ] -} - -SectionModifier."RecordMedia".0 { - SupportedDevice [ - "Headphone" - ] - EnableSequence [ - cdev "hw:PCH" - ] - - DisableSequence [ - cdev "hw:PCH" - ] - - TransitionSequence."ToModifierName" [ - cdev "hw:PCH" - ] - - # Optional TQ and ALSA PCMs - Value { - TQ Voice - CapturePCM "hw:1" - PlaybackVolume "name='Master Playback Volume',index=2" - PlaybackSwitch "name='Master Playback Switch',index=2" - } - -} - diff --git a/conf.d/alsa-sample/ucm.sample/README b/conf.d/alsa-sample/ucm.sample/README deleted file mode 100644 index e7f08ae..0000000 --- a/conf.d/alsa-sample/ucm.sample/README +++ /dev/null @@ -1,2 +0,0 @@ -Should match sound card name ex: "HDA Intel PCH" -cp -r . /usr/share/alsa/ucm diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 4719486..9293781 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -73,7 +73,7 @@ set (PKG_REQUIRED_LIST add_compile_options(-DCONTROL_DOSCRIPT_PRE="doscript") add_compile_options(-DCONTROL_CONFIG_PRE="onload") add_compile_options(-DCONTROL_CONFIG_POST="control" ) - add_compile_options(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/config.d:${CMAKE_INSTALL_PREFIX}/controler/config.d") + add_compile_options(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/config.d:${CMAKE_INSTALL_PREFIX}/controller/config.d") set(CONTROL_SUPPORT_LUA 1 CACHE BOOL "Active or not LUA Support") @@ -81,13 +81,13 @@ set (PKG_REQUIRED_LIST set(LUA_COMPILER "luac5.3" CACHE STRING "LUA syntaxe check") add_compile_options(-DCONTROL_SUPPORT_LUA) add_compile_options(-DCONTROL_LUA_EVENT="luaevt") - add_compile_options(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controler/ctl-lua.d") + add_compile_options(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controller/ctl-lua.d") else(CONTROL_SUPPORT_LUA) message(STATUS "Warning: LUA Without Support ") endif(CONTROL_SUPPORT_LUA) - set (CTL_PLUGIN_PRE "ctl-" CACHE STRING "Prefix for Controler share plugin") - set (CTL_PLUGIN_EXT ".ctlso" CACHE STRING "Postfix for Controler share plugin") + set (CTL_PLUGIN_PRE "ctl-" CACHE STRING "Prefix for Controller share plugin") + set (CTL_PLUGIN_EXT ".ctlso" CACHE STRING "Postfix for Controller share plugin") add_compile_options(-DCTL_PLUGIN_MAGIC=2468013579) add_compile_options(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}:${BINDINGS_INSTALL_DIR}/ctlplug:/usr/lib/afb/ctlplug") diff --git a/conf.d/project/alsa.d/asoundrc.sample b/conf.d/project/alsa.d/asoundrc.sample new file mode 100644 index 0000000..b208a09 --- /dev/null +++ b/conf.d/project/alsa.d/asoundrc.sample @@ -0,0 +1,146 @@ +# +# Author: Fulup Ar Foll +# Object: PCM hook type +# +# Test : Note: Jabra_USB=hw:v1340 +# Check SoundCard speaker-test -Dhw:v1340 -c2 -twav +# Check MixerPCM speaker-test -DMyMixerPCM -c2 -twav +# Check HookPCM speaker-test -DMyNavigationHook -c2 -twav +# Check NavPCM speaker-test -DMyNavPCM -c2 -twav +# MultiMedia aplay -DDMyNavPCM /usr/share/sounds/alsa/test.wav +# +# Bug/Feature: when softvol control is initialised from plugin and not +# from AGL binding. At 1st run ctl has invalid TLV and cannot be +# use. Bypass Solution: +# * start audio-binder before playing sound (binding create control before softvol plugin) +# * run a dummy aplay -DMyNavPCM "" to get a clean control +# +# References: https://www.spinics.net/lists/alsa-devel/msg54235.html +# -------------------------------------------------------------------- + +# Mixer PCM allow to play multiple stream simultaneously +# ------------------------------------------------------ +pcm.MyMixerPCM { + type dmix + ipc_key 1024 + ipc_key_add_uid false + ipc_perm 0666 # mixing for all users + + # Define target effective sound card (cannot be a plugin) + slave { + pcm "hw:v1340" #Jabra Solmate + period_time 0 + period_size 1024 + buffer_size 8192 + rate 44100 + } + + # DMIX can only map two channels + bindings { + 0 0 + 1 1 + } +} + +# Define a Hook_type with a private sharelib +# ------------------------------------------- +pcm_hook_type.MyHookPlugin { + install "AlsaInstallHook" + lib "/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build/Alsa-Plugin/Alsa-Policy-Hook/policy_hook_cb.so" +} + + +# Define a HookedPCM that point to Hook_type sharelib +# ---------------------------------------------------- +pcm.MyNavigationHook { + type hooks + slave.pcm "MyMixerPCM" + # Defined used hook sharelib and provide arguments/config to install func + hooks.0 { + type "MyHookPlugin" + hook_args { + verbose true # print few log messages (default false); + + # Every Call should return OK in order PCM to open (default timeout 100ms) + uri "ws://localhost:1234/api?token='audio-agent-token'" + request { + # Request autorisation to write on navigation + RequestNavigation { + api "control" + verb "dispatch" + query "{'target':'navigation', 'args':{'device':'Jabra SOLEMATE v1.34.0'}}" + } + } + # map event reception to self generated signal + event { + pause 30 + resume 31 + stop 3 + } + } + } +} + +# If hardware does not support mixer emulate it with softvol +# ----------------------------------------------------------- +pcm.MyMultimediaPCM { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "MyNavigationHook" + + # resolution=HAL(valMax+1) (default=256) + resolution 256 + + # name should match with HAL but do not set card=xx + control.name "Playback Navigation" + + # Make this plugin visible from aplay -L + hint { + show on + description "Navigation SolftVol PCM" + } +} + +# If hardware does not support mixer emulate it with softvol +# ----------------------------------------------------------- +pcm.MyNavPCM { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "MyNavigationHook" + + # resolution=HAL(valMax+1) (default=256) + resolution 256 + + # name should match with HAL but do not set card=xx + control.name "Playback Navigation" + + # Make this plugin visible from aplay -L + hint { + show on + description "Navigation SolftVol PCM" + } +} + +# If hardware does not support mixer emulate it with softvol +# ----------------------------------------------------------- +pcm.MyAlarmPCM { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "MyNavigationHook" + + # resolution=HAL(valMax+1) (default=256) + resolution 256 + + # name should match with HAL but do not set card=xx + control.name "Playback Navigation" + + # Make this plugin visible from aplay -L + hint { + show on + description "Navigation SolftVol PCM" + } +} + diff --git a/conf.d/project/alsa.d/ucm.sample/HDA Intel PCH.conf b/conf.d/project/alsa.d/ucm.sample/HDA Intel PCH.conf new file mode 100644 index 0000000..f6608a0 --- /dev/null +++ b/conf.d/project/alsa.d/ucm.sample/HDA Intel PCH.conf @@ -0,0 +1,6 @@ +Comment "Leon internal card" + +SectionUseCase."HiFi" { + File "HiFi.conf" + Comment "Default" +} diff --git a/conf.d/project/alsa.d/ucm.sample/HiFi.conf b/conf.d/project/alsa.d/ucm.sample/HiFi.conf new file mode 100644 index 0000000..9a53c8c --- /dev/null +++ b/conf.d/project/alsa.d/ucm.sample/HiFi.conf @@ -0,0 +1,84 @@ +SectionVerb { + EnableSequence [ + cdev "hw:PCH" + + cset "name='Master Playback Switch' on" + cset "name='Headphone Playback Switch' off" + cset "name='Speaker Playback Switch' on" + + cset "name='Capture Switch' on" + cset "name='Capture Volume' 39" + cset "name='Mic Boost Volume' 2" + cset "name='Internal Mic Boost Volume' 0" + #cset "name='Capture Source' 0" + ] + DisableSequence [ + ] + Value { + TQ "Music" + OutputDspName "speaker_eq" + PlaybackPCM "hw:PCH,0" + } +} + +SectionDevice."Headphone".0 { + Value { + JackName "Headphone Jack" + OutputDspName "Jheadphone" + } + EnableSequence [ + cdev "hw:PCH" + + cset "name='Speaker Playback Switch' off" + cset "name='Headphone Playback Switch' on" + ] + DisableSequence [ + cdev "hw:PCH" + + cset "name='Headphone Playback Switch' off" + cset "name='Speaker Playback Switch' on" + ] +} + +SectionDevice."Mic".0 { + Value { + JackName "Mic Jack" + } + EnableSequence [ + cdev "hw:PCH" + + #cset "name='Capture Source' 1" + ] + DisableSequence [ + cdev "hw:PCH" + + cset "name='Capture Source' 0" + ] +} + +SectionModifier."RecordMedia".0 { + SupportedDevice [ + "Headphone" + ] + EnableSequence [ + cdev "hw:PCH" + ] + + DisableSequence [ + cdev "hw:PCH" + ] + + TransitionSequence."ToModifierName" [ + cdev "hw:PCH" + ] + + # Optional TQ and ALSA PCMs + Value { + TQ Voice + CapturePCM "hw:1" + PlaybackVolume "name='Master Playback Volume',index=2" + PlaybackSwitch "name='Master Playback Switch',index=2" + } + +} + diff --git a/conf.d/project/alsa.d/ucm.sample/README b/conf.d/project/alsa.d/ucm.sample/README new file mode 100644 index 0000000..e7f08ae --- /dev/null +++ b/conf.d/project/alsa.d/ucm.sample/README @@ -0,0 +1,2 @@ +Should match sound card name ex: "HDA Intel PCH" +cp -r . /usr/share/alsa/ucm diff --git a/conf.d/project/config.d/onload-audio-control.json b/conf.d/project/config.d/onload-audio-control.json index 7180bd5..77a8fce 100644 --- a/conf.d/project/config.d/onload-audio-control.json +++ b/conf.d/project/config.d/onload-audio-control.json @@ -9,7 +9,7 @@ "label": "onload-default", "info": "onload initialisation config", "plugin": { - "label" : "MyPlug", + "label" : "_MyPlug", "sharelib": "ctl-audio-plugin-sample.ctlso", "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] }, @@ -28,11 +28,11 @@ "info": "Assert AlsaCore Presence", "api": "alsacore", "verb": "ping", - "args": "test" + "args": {"data": "none"} }, { "label": "onload-hal-lua", "info": "Load avaliable HALs", - "lua": "Audio_Init_Hal" + "lua": "_Alsa_Get_Hal" } ] }], @@ -43,20 +43,20 @@ "actions": { "label": "multimedia-control-lua", "info": "Call Lua Script function Test_Lua_Engin", - "lua": "Audio_Set_Multimedia" + "lua": "_Audio_Set_Multimedia" } }, { "label": "navigation", "actions": { "label": "navigation-control-lua", "info": "Call Lua Script to set Navigation", - "lua": "Audio_Set_Navigation" + "lua": "_Audio_Set_Navigation" } }, { "label": "emergency", "actions": { "label": "emergency-control-ucm", - "lua": "Audio_Set_Emergency" + "lua": "_Audio_Set_Emergency" } }, { "label": "multi-step-sample", @@ -79,7 +79,7 @@ }, { "label": "navigation-control-lua", "info": "Call Lua Script to set Navigation", - "lua": "Audio_Set_Navigation" + "lua": "_Audio_Set_Navigation" }] } ], diff --git a/conf.d/project/lua.d/doscript-helloworld.lua b/conf.d/project/lua.d/doscript-helloworld.lua index 64bc94a..a06c3db 100644 --- a/conf.d/project/lua.d/doscript-helloworld.lua +++ b/conf.d/project/lua.d/doscript-helloworld.lua @@ -21,7 +21,7 @@ --]] -function helloworld (request, query) +local function helloworld (request, query) AFB:notice ("LUA HelloWorld: Simple test query=%s", query); diff --git a/conf.d/project/lua.d/onload-audio-0utils.lua b/conf.d/project/lua.d/onload-audio-0utils.lua new file mode 100644 index 0000000..b8ecd7e --- /dev/null +++ b/conf.d/project/lua.d/onload-audio-0utils.lua @@ -0,0 +1,86 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Note: this file should be called before any other to assert declare function + is loaded before anything else. + + References: + http://lua-users.org/wiki/DetectingUndefinedVariables + +--]] + + +--=================================================== +--= Niklas Frykholm +-- basically if user tries to create global variable +-- the system will not let them!! +-- call GLOBAL_lock(_G) +-- +--=================================================== +function GLOBAL_lock(t) + local mt = getmetatable(t) or {} + mt.__newindex = lock_new_index + setmetatable(t, mt) +end + +--=================================================== +-- call GLOBAL_unlock(_G) +-- to change things back to normal. +--=================================================== +function GLOBAL_unlock(t) + local mt = getmetatable(t) or {} + mt.__newindex = unlock_new_index + setmetatable(t, mt) +end + +function lock_new_index(t, k, v) + if (string.sub(k,1,1) ~= "_") then + GLOBAL_unlock(_G) + error("GLOBALS are locked -- " .. k .. + " must be declared local or prefix with '_' for globals.", 2) + else + rawset(t, k, v) + end +end + +function unlock_new_index(t, k, v) + rawset(t, k, v) +end + +-- return serialised version of printable table +function Dump_Table(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. Dump_Table(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + + +-- simulate C prinf function +printf = function(s,...) + io.write(s:format(...)) + io.write("\n") + return +end + +-- lock global variable +GLOBAL_lock(_G) diff --git a/conf.d/project/lua.d/onload-audio-controls.lua b/conf.d/project/lua.d/onload-audio-controls.lua index 4849632..24c4f71 100644 --- a/conf.d/project/lua.d/onload-audio-controls.lua +++ b/conf.d/project/lua.d/onload-audio-controls.lua @@ -18,54 +18,145 @@ Provide sample policy function for AGL Advance Audio Agent --]] -function Audio_Init_CB (status, result, context) - print ("--inlua:Audio_Init_CB-- result=", Dump_Table(result)) - print ("--inlua:Audio_Init_CB-- context=", Dump_Table(context)) - - AFB:notice("Audio_Init_Hal_CB result='%s' context='%s'", result, context) +-- Global HAL registry +_Audio_Hal_Registry={} + +-- Callback when receiving HAL registry +function _Alsa_Get_Hal_CB (error, result, context) + -- Initialise an empty table + local registry={} + + -- Only process when response is valid + if (error) then + AFB_ErrOr ("[Audio_Init_CB] ErrOr result=%s", result) + return + end + + -- Extract response from result + local response=result["response"] + + -- Index HAL Bindings APIs by shortname + for key,value in pairs(response) do + registry[value["shortname"]]=value["api"] + end + + -- store Exiting HAL for further use + printf ("-- [Audio_Init_CB] -- Audio_register_Hal=%s", Dump_Table(registry)) + _Audio_Hal_Registry=registry end -- Function call at binding load time -function Audio_Init_Hal(args, query) +function _Alsa_Get_Hal(args) - local nested = { - ["next1"]=1234, - ["next2"]="nested", - ["next3"]=9999, - } - local context = { - ["arg1"]=1234, - ["arg2"]=nested, - ["arg3"]=5678, - } + printf ("[-- Audio_Get_Hal --] args=%s", Dump_Table(argsT)) + + -- Query AlsaCore for Active HALs (no query, no context) + AFB:service ('alsacore', 'hallist', {}, "_Alsa_Get_Hal_CB", {}) + +end - print ("--inlua:Audio_Init-- response=", Dump_Table(responseT)) +-- In sample configuration Query/Args parsing is common to all audio control +local function Audio_Parse_Request (source, args, query) - print("myplug=", Dump_Table(MyPlug)); + local apihal={} - -- This routine is defined in C sample plugin - local status=MyPlug:Lua2cHelloWorld1(nested) - - -- query asynchronously loaded HAL - AFB:service ('alsacore', 'hallist', {}, "Audio_Init_CB", context) - + -- In this test we expect targeted device to be given from query (could come for args as well) + if (query == nil ) then + AFB:error ("--LUA:Audio_Set_Navigation query should contain and args with targeted apihal|device") + return -- refuse control + end + + -- Alsa Hook plugin asound sample config provides target sound card by name + if (query["device"] ~= nil) then + apihal=_Audio_Hal_Registry[query["device"]] + end + + -- HTML5 test page provides directly HAL api. + if (query["apihal"] ~= nil) then + apihal= query["apihal"] + end + + -- if requested HAL is not found then deny the control + if (apihal == nil) then + AFB:error ("--LUA:Audio_Set_Navigation No Active HAL Found") + return -- refuse control + end + + -- return api or nil when not found + return apihal end -function Audio_Set_Navigation(args, query) +-- Set Navigation lower sound when play +function _Audio_Set_Navigation(source, args, query) + + -- in strict mode every variables should be declared + local err=0 + local ctlhal={} + local response={} + local apihal={} + + AFB:notice ("LUA:Audio_Set_Use_Case source=%d args=%s query=%s", source, args, query); + + -- Parse Query/Args and if HAL not found then refuse access + apihal= Audio_Parse_Request (source, args, query) + if (apihal == nil) then return 1 end + - AFB:notice ("LUA:Audio_Set_Use_Case args=%s query=%s", args, query); + -- if source < 0 then Alsa HookPlugin is closing PCM + if (source < 0) then + -- Ramp Up Multimedia channel synchronously + ctlhal={['label']='Master_Playback_Volume', ['val']=100} + err, response= AFB:servsync (apihal, 'ctlset',ctlhal) + else + -- Ramp Down Multimedia channel synchronously + ctlhal={['label']='Master_Playback_Volume', ['val']=50} + err, response= AFB:servsync (apihal, 'ctlset',ctlhal) + end - -- synchronous call to alsacore service - local error,data= AFB:callsync ('alsacore', 'ping', {}) - if (error) then - AFB:error ("LUA:Audio_Set_Use_Case FAIL args=%s", args) - else - AFB:notice ("--LUA:Audio_Set_Use_Case DONE args=%s response=%s", args, data["response"]) + if (err) then + AFB:error("--LUA:Audio_Set_Navigation halapi=%s refuse ctl=%s", apihal, ctlhal) + return 1 -- control refused end - -- return OK - return 0 + + return 0 -- control accepted end +-- Select Multimedia mode +function _Audio_Set_Multimedia (source, args, query) + + -- in strict mode every variables should be declared + local err=0 + local ctlhal={} + local response={} + local apihal={} + + AFB:notice ("LUA:Audio_Set_Use_Case source=%d args=%s query=%s", source, args, query); + + -- Parse Query/Args and if HAL not found then refuse access + apihal= Audio_Parse_Request (source, args, query) + if (apihal == nil) then return 1 end + + + -- if Mumtimedia control only increase volume on open + if (source >= 0) then + -- Ramp Down Multimedia channel synchronously + ctlhal={['label']='Master_Playback_Volume', ['val']=100} + err, response= AFB:servsync (apihal, 'ctlset',ctlhal) + end + + if (err) then + AFB:error("--LUA:Audio_Set_Navigation halapi=%s refuse ctl=%s", apihal, ctlhal) + return 1 -- control refused + end + + + return 0 -- control accepted +end + +-- Select Emergency Mode +function _Audio_Set_Emergency(source, args, query) + return 1 -- Always refuse in this test +end diff --git a/conf.d/project/lua.d/onload-audio-oncall.lua b/conf.d/project/lua.d/onload-audio-oncall.lua index 08b25e5..23b538e 100644 --- a/conf.d/project/lua.d/onload-audio-oncall.lua +++ b/conf.d/project/lua.d/onload-audio-oncall.lua @@ -18,18 +18,18 @@ Provide sample LUA routines to be used with AGL control "lua_docall" API --]] --- global counter to keep track of calls -count=0 +--global counter to keep track of calls +_count=0 -- Display receive arguments and echo them to caller -function Simple_Echo_Args (request, args) - count=count+1 +function _Simple_Echo_Args (request, args) + _count=_count+1 AFB:notice("LUA OnCall Echo Args count=%d args=%s", count, args) print ("--inlua-- args=", Dump_Table(args)) local response={ - ["count"]=count, + ["count"]=_count, ["args"]=args, } @@ -37,7 +37,7 @@ function Simple_Echo_Args (request, args) AFB:success (request, {["func"]="Simple_Echo_Args", ["ret1"]=5678, ["ret2"]="abcd"}) end -function Test_Async_CB (request, result, context) +local function Test_Async_CB (request, result, context) response={ ["result"]=result, ["context"]=context, @@ -47,7 +47,7 @@ function Test_Async_CB (request, result, context) AFB:success (request, response) end -function Test_Call_Async (request, args) +function _Test_Call_Async (request, args) local context={ ["value1"]="abcd", ["value2"]=1234 @@ -57,7 +57,7 @@ function Test_Call_Async (request, args) AFB:service("alsacore","ping", "Test_Async_CB", context) end -function Test_Call_Sync (request, args) +function _Test_Call_Sync (request, args) AFB:notice ("Test_Call_Sync args=%s", args) local err, response= AFB:service_sync ("alsacore","ping", args) diff --git a/conf.d/project/lua.d/onload-audio-timer.lua b/conf.d/project/lua.d/onload-audio-timer.lua index 5f25de7..db7a937 100644 --- a/conf.d/project/lua.d/onload-audio-timer.lua +++ b/conf.d/project/lua.d/onload-audio-timer.lua @@ -19,11 +19,10 @@ --]] -- Create event on Lua script load -print ("*** Create MyTestEvent ***") -MyEventHandle= AFB:evtmake("MyTestEvent") +local MyEventHandle=AFB:evtmake("MyTestEvent") -- Call count time every delay/ms -function Timer_Test_CB (timer, context) +local function Timer_Test_CB (timer, context) local evtinfo= AFB:timerget(timer) print ("timer=", Dump_Table(evtinfo)) @@ -37,7 +36,7 @@ function Timer_Test_CB (timer, context) end -- sendback event depending on count and delay -function Simple_Timer_Test (request, args) +function _Simple_Timer_Test (request, args) local context = { ["info"]="My 1st private Event", @@ -68,6 +67,3 @@ function Simple_Timer_Test (request, args) return 0 end - - - diff --git a/conf.d/project/lua.d/onload-audio-utils.lua b/conf.d/project/lua.d/onload-audio-utils.lua deleted file mode 100644 index 40ef8a3..0000000 --- a/conf.d/project/lua.d/onload-audio-utils.lua +++ /dev/null @@ -1,32 +0,0 @@ ---[[ - Copyright (C) 2016 "IoT.bzh" - Author Fulup Ar Foll - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ---]] - - --- return serialised version of printable table -function Dump_Table(o) - if type(o) == 'table' then - local s = '{ ' - for k,v in pairs(o) do - if type(k) ~= 'number' then k = '"'..k..'"' end - s = s .. '['..k..'] = ' .. Dump_Table(v) .. ',' - end - return s .. '} ' - else - return tostring(o) - end -end diff --git a/data/default-control-policy.json b/data/default-control-policy.json index 30cd1ce..c6f8bd0 100644 --- a/data/default-control-policy.json +++ b/data/default-control-policy.json @@ -6,7 +6,7 @@ "version": "1.0" }, "onload": { - "info": "controler initialisation config", + "info": "controller initialisation config", "plugin": "sample-audio-policy.so", "actions": [ { diff --git a/htdocs/AudioBinding.js b/htdocs/AudioBinding.js index 607d31c..4d14600 100644 --- a/htdocs/AudioBinding.js +++ b/htdocs/AudioBinding.js @@ -94,7 +94,6 @@ var selectobj = document.getElementById(elemid); if (!selectobj) { - console.log ("****** elemid=%s does not exit in HTML page ****", elemid); return; } diff --git a/htdocs/alsa-hal.html b/htdocs/alsa-hal.html index f1d5aaf..013c547 100644 --- a/htdocs/alsa-hal.html +++ b/htdocs/alsa-hal.html @@ -27,15 +27,15 @@
      -
    1. -
    2. -
    3. -
    4. +
    5. +
    6. +
    7. +

    8. -
    9. -
    10. -
    11. -
    12. +
    13. +
    14. +
    15. +

    16. diff --git a/htdocs/audio-control.html b/htdocs/audio-control.html index d51ae55..6b7872f 100644 --- a/htdocs/audio-control.html +++ b/htdocs/audio-control.html @@ -5,14 +5,15 @@ - - + -

      Simple Audio Control test

      - +

      Simple Audio Control Test

      +

      - + Selected HAL + + API Verbosity
      -
      +
        -
      1. -
      2. -
      3. +
      4. +
      5. +

      6. -
      7. +
      8. -
      9. +
      diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index a5d9f8e..235c3b0 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -43,7 +43,7 @@ AudioCommonLib.c - + ctl-binding.c ctl-dispatch.c ctl-lua.c @@ -234,7 +234,7 @@ - + ../../../opt/include @@ -243,15 +243,15 @@ /usr/include/json-c /usr/include/lua5.3 Audio-Common - build/Controler-afb + build/Controller-afb - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_DOSCRIPT_PRE="doscript" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -265,79 +265,60 @@ - + ../../../opt/include/afb - Controler-afb + Controller-afb /usr/include/json-c /usr/include/lua5.3 Audio-Common ../../../opt/include - build/Controler-afb + build/Controller-afb - - + + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + ../../../opt/include/afb + Controller-afb /usr/include/json-c /usr/include/lua5.3 Audio-Common - build/Controler-afb + ../../../opt/include + build/Controller-afb - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - control_afb_EXPORTS - - + ../../../opt/include/afb - Controler-afb + Controller-afb /usr/include/json-c - build/Controler-afb + build/Controller-afb - + ../../../opt/include/afb - Controler-afb + Controller-afb /usr/include/json-c /usr/include/lua5.3 - build/Controler-afb + build/Controller-afb - + ../../../opt/include/afb - Controler-afb - /usr/include/json-c + Controller-afb ../../../opt/include - build/Controler-afb + build/Controller-afb @@ -462,12 +443,12 @@ build/Alsa-Plugin/Alsa-Policy-Hook - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_DOSCRIPT_PRE="doscript" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -499,7 +480,7 @@ /usr/include/json-c /usr/include/lua5.3 Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin /usr/include/alsa build/Common @@ -507,11 +488,11 @@ CONTROL_CDEV_RX="/dev/inic-usb-crx" CONTROL_CDEV_TX="/dev/inic-usb-ctx" - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -534,11 +515,11 @@ /usr/include/lua5.3 - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -561,7 +542,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin ../../../opt/include/afb HAL-afb/HAL-plugin @@ -611,7 +592,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin ../../../opt/include/afb HAL-afb/Unicens-USB @@ -633,7 +614,7 @@ /usr/include/json-c /usr/include/lua5.3 Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin ../../../opt/include/afb HighLevel-afb @@ -641,11 +622,11 @@ build/HighLevel-afb - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -667,15 +648,15 @@ /usr/include/json-c /usr/include/lua5.3 Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -1058,7 +1039,8 @@ - + @@ -1105,16 +1087,16 @@ ../../../opt/include/alsa /usr/include/json-c - Shared-Interface + Audio-Common ../../../opt/include - build/ALSA-afb + build/Alsa-afb - build/ALSA-afb + build/Alsa-afb @@ -1123,9 +1105,9 @@ ../../../opt/include/alsa /usr/include/json-c - Shared-Interface + Audio-Common ../../../opt/include - build/ALSA-afb + build/Alsa-afb @@ -1134,9 +1116,9 @@ ../../../opt/include/alsa /usr/include/json-c - Shared-Interface + Audio-Common ../../../opt/include - build/ALSA-afb + build/Alsa-afb @@ -1145,28 +1127,76 @@ ../../../opt/include/alsa /usr/include/json-c - Shared-Interface + Audio-Common ../../../opt/include - build/ALSA-afb + build/Alsa-afb + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + Audio-Common + /usr/include/json-c + build/Audio-Common + - + + + + control_afb_EXPORTS + + + + + + + control_afb_EXPORTS + + + + + + control_afb_EXPORTS + - + + + audio_plugin_sample_EXPORTS + - + + + control_afb_EXPORTS + - Shared-Interface + Audio-Common ../../../opt/include build/HAL-afb/HAL-interface @@ -1187,7 +1217,7 @@ flavor2="3"> - Shared-Interface + Audio-Common build/HAL-afb/HAL-interface @@ -1220,7 +1250,7 @@ - + Shared-Interface HAL-afb/HAL-interface @@ -1230,7 +1260,7 @@ - + HAL-afb/HAL-interface build/HAL-afb/Unicens-USB @@ -1300,15 +1330,16 @@ build/Alsa-Plugin/Alsa-Policy-Hook - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_DOSCRIPT_PRE="doscript" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 @@ -1323,21 +1354,11 @@ ../../../opt/include/afb - ALSA-afb - - - - - - - ../../../opt/include/afb - Shared-Interface - /usr/include/json-c - build/Shared-Interface + Alsa-afb - + ../../../opt/include @@ -1346,24 +1367,24 @@ /usr/include/json-c /usr/include/lua5.3 Audio-Common - build/Controler-afb + build/Controller-afb - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_DOSCRIPT_PRE="doscript" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA CTL_PLUGIN_MAGIC=2468013579 MAX_LINEAR_DB_SCALE=24 MAX_SND_CARD=16 NATIVE_LINUX TLV_BYTE_SIZE=256 - control_afb_EXPORTS @@ -1384,7 +1405,7 @@ HAL-afb/HDA-intel ../../../opt/include/alsa /usr/include/json-c - Shared-Interface + Audio-Common HAL-afb/HAL-interface ../../../opt/include build/HAL-afb/HDA-intel @@ -1395,10 +1416,10 @@ HAL-afb/Jabra-Solemate + ../../../opt/include/afb ../../../opt/include/alsa /usr/include/json-c - ../../../opt/include/afb - Shared-Interface + Audio-Common HAL-afb/HAL-interface ../../../opt/include build/HAL-afb/Jabra-Solemate @@ -1412,7 +1433,7 @@ HAL-afb/Scarlett-Focusrite ../../../opt/include/alsa /usr/include/json-c - Shared-Interface + Audio-Common HAL-afb/HAL-interface ../../../opt/include build/HAL-afb/Scarlett-Focusrite @@ -1462,11 +1483,11 @@ /usr/include/lua5.3 - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controler/config.d" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" CONTROL_CONFIG_POST="control" CONTROL_CONFIG_PRE="onload" CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controler/ctl-lua.d" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" CONTROL_MAXPATH_LEN=255 CONTROL_ONLOAD_DEFAULT="onload-default" CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" @@ -1522,65 +1543,65 @@ - + Audio-Common - build/Controler-afb + build/Controller-afb control_afb_EXPORTS - + Audio-Common - build/Controler-afb + build/Controller-afb control_afb_EXPORTS - + Audio-Common - build/Controler-afb + build/Controller-afb control_afb_EXPORTS - + Audio-Common - build/Controler-afb + build/Controller-afb control_afb_EXPORTS - + - build/Controler-afb + build/Controller-afb audio_plugin_sample_EXPORTS - + Audio-Common - build/Controler-afb + build/Controller-afb control_afb_EXPORTS @@ -1725,7 +1746,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin /usr/include/alsa build/Common @@ -1738,7 +1759,7 @@ - + CONTROL_DOSCRIPT_PRE="doscript" @@ -1761,7 +1782,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin ../../../opt/include/afb HAL-afb/HAL-plugin @@ -1817,7 +1838,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin ../../../opt/include/afb HAL-afb/Unicens-USB @@ -1834,7 +1855,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin ../../../opt/include/afb HighLevel-afb @@ -1851,7 +1872,7 @@ Audio-Common - build/Controler-afb + build/Controller-afb build/HAL-afb/HAL-plugin @@ -1861,5 +1882,685 @@ + + + GNU|GNU + false + false + + + + + + + + + + true + + + + build + ${MAKE} -f Makefile install + ${MAKE} -f Makefile clean + build/CMakeFiles/feature_tests.bin + + + + + build + cmake .. + true + + + + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Alsa-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + alsa_lowlevel_EXPORTS + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Audio-Common + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + + + + + + + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + ../../../opt/include/afb + Controller-afb + /usr/include/json-c + build/Controller-afb + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + Audio-Common + build/HAL-afb/HAL-interface + + + + + + + Audio-Common + build/HAL-afb/HAL-interface + + + + + + + build/HAL-afb/HAL-interface + + + + + + + + + + + + + + + + + + + + + + + Shared-Interface + HAL-afb/HAL-interface + build/HAL-afb/Unicens-USB + + + + + + + HAL-afb/HAL-interface + build/HAL-afb/Unicens-USB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + build/Alsa-Plugin/Alsa-Policy-Hook + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + PIC + TLV_BYTE_SIZE=256 + policy_hook_cb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + /usr/include/alsa + build/Common + + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + + + + + + + ../../../opt/include/afb + HAL-afb/HAL-interface + + + + + + + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + ../../../opt/include/afb + HAL-afb/HAL-plugin + + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include/afb + HAL-afb/HDA-intel + Audio-Common + HAL-afb/HAL-interface + build/HAL-afb/HDA-intel + + + + + + + HAL-afb/Jabra-Solemate + ../../../opt/include/afb + Audio-Common + HAL-afb/HAL-interface + build/HAL-afb/Jabra-Solemate + + + + + + + ../../../opt/include/afb + HAL-afb/Scarlett-Focusrite + Audio-Common + HAL-afb/HAL-interface + build/HAL-afb/Scarlett-Focusrite + + + + + + + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + ../../../opt/include/afb + HAL-afb/Unicens-USB + + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + ../../../opt/include/afb + HighLevel-afb + Shared-Interface + build/HighLevel-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + diff --git a/nbproject/project.xml b/nbproject/project.xml index 7c62c94..db3bdab 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -29,6 +29,10 @@ LocalHostNoTrace 0 + + Local_Raw_Controller + 0 + false -- cgit 1.2.3-korg From 082d083a96f4be23ea6f54fc26eeaece7cfa4507 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Fri, 18 Aug 2017 01:43:18 +0200 Subject: Documented Controller standalone mode and provided a sample config. --- Controller-afb/README.md | 11 +++ .../project/config.d/onload-daemon-standalone.json | 72 ++++++++++++++++++ .../lua.d/standalone-sample/onload-daemon-00.lua | 86 ++++++++++++++++++++++ .../lua.d/standalone-sample/onload-daemon-01.lua | 57 ++++++++++++++ 4 files changed, 226 insertions(+) create mode 100644 conf.d/project/config.d/onload-daemon-standalone.json create mode 100644 conf.d/project/lua.d/standalone-sample/onload-daemon-00.lua create mode 100644 conf.d/project/lua.d/standalone-sample/onload-daemon-01.lua diff --git a/Controller-afb/README.md b/Controller-afb/README.md index 403f637..e6cab72 100644 --- a/Controller-afb/README.md +++ b/Controller-afb/README.md @@ -183,6 +183,17 @@ input parameter. When funcname is not given by default the controller try to exe When executed from controller Lua script may use any AppFw Apis as well as any L2C user defined commands in plugin. +### Running as Standalone Controller + +Controller is a standard binding and can then be started independently of AAAA. When started with from build repository with +``` +afb-daemon --port=1234 --workdir=. --roothttp=../htdocs --tracereq=common --token= --verbose --binding=./Controller-afb/afb-control-afb.so +``` + +Afb-Daemon only load controller bindings without search for the other binding. In this case the name of the process is not change +to afb-audio and controller binding will search for a configuration file name 'onload-daemon-xxx.json'. This model can be used +to implement for testing purpose or simply to act as the glue in between a UI and other binder/services. + ## Config Sample Here after a simple configuration sample. diff --git a/conf.d/project/config.d/onload-daemon-standalone.json b/conf.d/project/config.d/onload-daemon-standalone.json new file mode 100644 index 0000000..de52c22 --- /dev/null +++ b/conf.d/project/config.d/onload-daemon-standalone.json @@ -0,0 +1,72 @@ +{ + "$schema": "ToBeDone", + "metadata": { + "label": "sample-standalone-control", + "info": "Minimal Standalone Controller Config", + "version": "1.0" + }, + "onload": [{ + "label": "onload-default", + "info": "onload initialisation config", + "actions": + { + "label": "control-init", + "lua": "_Control_Init" + } + }], + "controls": + [ + { + "label": "Button-1", + "actions": { + "label": "Action on Button One", + "lua": "_Button_Press", + "args": { + "button": 1 + } + } + }, { + "label": "Button-1", + "actions": { + "label": "Action on Button Two", + "lua": "_Button_Press", + "args": { + "button": 2 + } + } + }, { + "label": "Button-1", + "actions": { + "label": "Action on Button Three", + "lua": "_Button_Press", + "args": { + "button": 3 + } + } + } + ], + "events": + [ + { + "label": "Event1", + "actions": { + "label": "Action Event 1", + "lua": "_Event_Received", + "args": { + "evtname": "xxx" + } + } + }, + { + "label": "Event2", + "actions": { + "label": "Action Event 2", + "lua": "_Event_Received", + "args": { + "evtname": "yyy" + } + } + } + ] +} + diff --git a/conf.d/project/lua.d/standalone-sample/onload-daemon-00.lua b/conf.d/project/lua.d/standalone-sample/onload-daemon-00.lua new file mode 100644 index 0000000..b8ecd7e --- /dev/null +++ b/conf.d/project/lua.d/standalone-sample/onload-daemon-00.lua @@ -0,0 +1,86 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Note: this file should be called before any other to assert declare function + is loaded before anything else. + + References: + http://lua-users.org/wiki/DetectingUndefinedVariables + +--]] + + +--=================================================== +--= Niklas Frykholm +-- basically if user tries to create global variable +-- the system will not let them!! +-- call GLOBAL_lock(_G) +-- +--=================================================== +function GLOBAL_lock(t) + local mt = getmetatable(t) or {} + mt.__newindex = lock_new_index + setmetatable(t, mt) +end + +--=================================================== +-- call GLOBAL_unlock(_G) +-- to change things back to normal. +--=================================================== +function GLOBAL_unlock(t) + local mt = getmetatable(t) or {} + mt.__newindex = unlock_new_index + setmetatable(t, mt) +end + +function lock_new_index(t, k, v) + if (string.sub(k,1,1) ~= "_") then + GLOBAL_unlock(_G) + error("GLOBALS are locked -- " .. k .. + " must be declared local or prefix with '_' for globals.", 2) + else + rawset(t, k, v) + end +end + +function unlock_new_index(t, k, v) + rawset(t, k, v) +end + +-- return serialised version of printable table +function Dump_Table(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. Dump_Table(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + + +-- simulate C prinf function +printf = function(s,...) + io.write(s:format(...)) + io.write("\n") + return +end + +-- lock global variable +GLOBAL_lock(_G) diff --git a/conf.d/project/lua.d/standalone-sample/onload-daemon-01.lua b/conf.d/project/lua.d/standalone-sample/onload-daemon-01.lua new file mode 100644 index 0000000..7b22db0 --- /dev/null +++ b/conf.d/project/lua.d/standalone-sample/onload-daemon-01.lua @@ -0,0 +1,57 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Note: this file should be called before any other to assert declare function + is loaded before anything else. + + References: + http://lua-users.org/wiki/DetectingUndefinedVariables + +--]] + +-- Set Navigation lower sound when play +function _Control_Init(source, args) + + -- in strict mode every variables should be declared + local err=0 + + AFB:notice ("Control_Init args=%s", args); + + return 0 -- control accepted +end + +-- Set Navigation lower sound when play +function _Button_Press(source, args, query) + + -- in strict mode every variables should be declared + local err=0 + + AFB:notice ("Button_Press button=%s", args["button"]); + + return 0 -- control accepted +end + +-- Set Navigation lower sound when play +function _Event_Received(source, args, query) + + -- in strict mode every variables should be declared + local err=0 + + AFB:notice ("Event_Received event=%s", args["evtname"]); + + return 0 -- control accepted +end + -- cgit 1.2.3-korg From 6fa8948541948946e3b3e4d93d064e15e33f8e97 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Wed, 16 Aug 2017 18:50:57 +0200 Subject: Integrate OpenAPI .h file generation. Change-Id: I166d5019893308f239c3485ae03e87bf4a05cc5d Signed-off-by: Romain Forlot # Conflicts: # Controler-afb/CMakeLists.txt --- Controller-afb/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Controller-afb/CMakeLists.txt b/Controller-afb/CMakeLists.txt index a9e8e60..7ac0842 100644 --- a/Controller-afb/CMakeLists.txt +++ b/Controller-afb/CMakeLists.txt @@ -43,6 +43,7 @@ PROJECT_TARGET_ADD(control-afb) # Generate API-v2 hat from OpenAPI json definition SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) + SET_OPENAPI_FILENAME("afb-control-afb") # Binder exposes a unique public entry point SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES PREFIX "afb-" -- cgit 1.2.3-korg From 3648e16e17a908e7f08bde789fefe3abc6981544 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 18 Aug 2017 10:45:11 +0200 Subject: Latest app-templates features integration - CMake >= 3.6 mandatory - Change DATA and HTDOCS targets methods to use macro add_input_files() - header generated from OpenAPI file using BINDINGV2 label and set_openapi_filename() macro. - Adjusted README to reflect new cmake requirement Change-Id: I8da515b98c1877d5be5e51f2bf94d691ac3cefb7 Signed-off-by: Romain Forlot --- CMakeLists.txt | 2 +- Controller-afb/CMakeLists.txt | 19 ++----------------- README.md | 5 ++++- conf.d/app-templates | 2 +- conf.d/project/config.d/CMakeLists.txt | 16 ++++------------ conf.d/project/lua.d/CMakeLists.txt | 16 ++++------------ data/CMakeLists.txt | 15 +-------------- htdocs/CMakeLists.txt | 12 +----------- 8 files changed, 18 insertions(+), 69 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index faef509..b8bb607 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ########################################################################### -CMAKE_MINIMUM_REQUIRED(VERSION 3.3) +CMAKE_MINIMUM_REQUIRED(VERSION 3.6) # Do not change this file, config is located into conf.d include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake) diff --git a/Controller-afb/CMakeLists.txt b/Controller-afb/CMakeLists.txt index 7ac0842..d1b430b 100644 --- a/Controller-afb/CMakeLists.txt +++ b/Controller-afb/CMakeLists.txt @@ -16,18 +16,6 @@ # limitations under the License. ########################################################################### - -# Generate API-v2 hat from OpenAPI json definition -macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME) - add_custom_command(OUTPUT ${API_DEF_NAME}.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${API_DEF_NAME}.json - COMMAND afb-genskel ${API_DEF_NAME}.json >${API_DEF_NAME}.h - ) - add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h) - add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI) -endmacro(SET_TARGET_GENSKEL) - # Include LUA only when requested if(CONTROL_SUPPORT_LUA) message(STATUS "Notice: LUA Controler Support Selected") @@ -40,14 +28,11 @@ PROJECT_TARGET_ADD(control-afb) # Define project Targets ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-timer.c ctl-dispatch.c ${CTL_LUA_SOURCE}) - # Generate API-v2 hat from OpenAPI json definition - SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) - - SET_OPENAPI_FILENAME("afb-control-afb") + SET_OPENAPI_FILENAME("ctl-apidef") # Binder exposes a unique public entry point SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES PREFIX "afb-" - LABELS "BINDING" + LABELS "BINDINGV2" LINK_FLAGS ${BINDINGS_LINK_FLAG} OUTPUT_NAME ${TARGET_NAME} ) diff --git a/README.md b/README.md index 5d03694..54bf154 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,20 @@ git pull --recurse-submodules https://github.com/iotbzh/audio-bindings # Specific Dependencies + * cmake >= 3.6 * alsa-devel >= 1.1.2 Warning some distro like Fedora-25 still ship version 1.1.1 as default * lua >= 5.3 Most distribution only ship version 5.2 but binary package should be easy to find ``` OpenSuse + - cmake 3.6 Take the Tumbleweed version https://software.opensuse.org/ymp/openSUSE:Factory/standard/cmake.ymp?base=openSUSE%3AFactory&query=cmake - LUA-5.3-devel https://software.opensuse.org//download.html?project=devel%3Alanguages%3Alua&package=lua53 - Alsa-devel zypper --install alsa-devel # 42.3 is shipped default with 1.1.4 Fedora 26 (out of the box) - - Lua 5.3 + - cmake 3.6 + - Lua 5.3 - Alsa-devel 1.1.4 ``` diff --git a/conf.d/app-templates b/conf.d/app-templates index 8967162..421f628 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 8967162dd12bce89f9ae27f5c9bce7b78624e3fd +Subproject commit 421f62833dc53ab95648951e75827deb2d9d20b2 diff --git a/conf.d/project/config.d/CMakeLists.txt b/conf.d/project/config.d/CMakeLists.txt index 229cf2d..8070997 100644 --- a/conf.d/project/config.d/CMakeLists.txt +++ b/conf.d/project/config.d/CMakeLists.txt @@ -24,17 +24,9 @@ PROJECT_TARGET_ADD(ctl-config.d) file(GLOB XML_FILES "*.json") - add_custom_target(${TARGET_NAME} - DEPENDS ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - ) + add_input_files("${XML_FILES}") - # check XML schema before pushing config - add_custom_command( - DEPENDS ${XML_FILES} - OUTPUT ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - # COMMAND xmllint -schema ${XML_SCHEMA} ${XML_FILES} --noout (Fulup we miss this for JSON) - COMMAND mkdir -p ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND touch ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND cp -r ${XML_FILES} ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "DATA" + OUTPUT_NAME ${TARGET_NAME} ) - diff --git a/conf.d/project/lua.d/CMakeLists.txt b/conf.d/project/lua.d/CMakeLists.txt index ecf1e6d..5cd61f2 100644 --- a/conf.d/project/lua.d/CMakeLists.txt +++ b/conf.d/project/lua.d/CMakeLists.txt @@ -24,17 +24,9 @@ PROJECT_TARGET_ADD(ctl-lua.d) file(GLOB LUA_FILES "*.lua") - add_custom_target(${TARGET_NAME} - DEPENDS ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - ) + add_input_files("${LUA_FILES}") - # check XML schema before pushing config - add_custom_command( - DEPENDS ${LUA_FILES} - OUTPUT ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND ${LUA_COMPILER} ${LUA_FILES} - COMMAND mkdir -p ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND touch ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND cp -r ${LUA_FILES} ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "DATA" + OUTPUT_NAME ${TARGET_NAME} ) - diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 55ee664..3b052c9 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -25,20 +25,7 @@ PROJECT_TARGET_ADD(Control_config) file(GLOB XML_FILES "*.json") - add_custom_target(${TARGET_NAME} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} - ) - - # check XML schema before pushing config - add_custom_command( - DEPENDS ${XML_FILES} - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - # COMMAND xmllint -schema ${XML_SCHEMA} ${XML_FILES} --noout (Fulup we miss this for JSON) - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} - COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} - COMMAND cp -r ${XML_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} - ) + add_input_files("${XML_FILES}") SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES LABELS "DATA" diff --git a/htdocs/CMakeLists.txt b/htdocs/CMakeLists.txt index e85ca3c..322033d 100644 --- a/htdocs/CMakeLists.txt +++ b/htdocs/CMakeLists.txt @@ -25,17 +25,7 @@ PROJECT_TARGET_ADD(htdocs) file(GLOB SOURCE_FILES "*.html" "*.js" "*.jpg" "*.css") - add_custom_target(${TARGET_NAME} - DEPENDS ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - ) - - add_custom_command( - DEPENDS ${SOURCE_FILES} - OUTPUT ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND mkdir -p ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND touch ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - COMMAND cp -r ${SOURCE_FILES} ${PROJECT_PKG_BUILD_DIR}/${TARGET_NAME} - ) + add_input_files("${SOURCE_FILES}") SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES LABELS "HTDOCS" -- cgit 1.2.3-korg From a39532c4d86e4b31c3ddb2e9b132ca87865d7b58 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 18 Aug 2017 12:43:09 +0200 Subject: CMake minimal version set to 3.5 Change-Id: Ic0cc88d4b423deb3ba187b59f3e0caad0711fd4d Signed-off-by: Romain Forlot --- CMakeLists.txt | 2 +- README.md | 3 --- conf.d/app-templates | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8bb607..22adb2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ########################################################################### -CMAKE_MINIMUM_REQUIRED(VERSION 3.6) +CMAKE_MINIMUM_REQUIRED(VERSION 3.5) # Do not change this file, config is located into conf.d include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake) diff --git a/README.md b/README.md index 54bf154..2063677 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,16 @@ git pull --recurse-submodules https://github.com/iotbzh/audio-bindings # Specific Dependencies - * cmake >= 3.6 * alsa-devel >= 1.1.2 Warning some distro like Fedora-25 still ship version 1.1.1 as default * lua >= 5.3 Most distribution only ship version 5.2 but binary package should be easy to find ``` OpenSuse - - cmake 3.6 Take the Tumbleweed version https://software.opensuse.org/ymp/openSUSE:Factory/standard/cmake.ymp?base=openSUSE%3AFactory&query=cmake - LUA-5.3-devel https://software.opensuse.org//download.html?project=devel%3Alanguages%3Alua&package=lua53 - Alsa-devel zypper --install alsa-devel # 42.3 is shipped default with 1.1.4 Fedora 26 (out of the box) - - cmake 3.6 - Lua 5.3 - Alsa-devel 1.1.4 ``` diff --git a/conf.d/app-templates b/conf.d/app-templates index 421f628..aa763dd 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 421f62833dc53ab95648951e75827deb2d9d20b2 +Subproject commit aa763ddec685dc44bcb5d44718d78f3692d4f0dc -- cgit 1.2.3-korg From de625486c6dcfd3372a46d43988e5d5f809d2da9 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 18 Aug 2017 16:33:18 +0200 Subject: Change how to define compile options Move specific compilation options to the target it is related keep global compilation option in config.cmake then variable can be correctly evaluated and use with the correct values (CMAKE_INSTALL_PREFIX isn't the same before common.cmake inclusion and after.) Change-Id: Ia3c3fe6bc6fcdcb79858f233b108b9ee1e071131 Signed-off-by: Romain Forlot --- Controller-afb/CMakeLists.txt | 16 +++++++++- conf.d/cmake/config.cmake | 71 ++++++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/Controller-afb/CMakeLists.txt b/Controller-afb/CMakeLists.txt index d1b430b..c128184 100644 --- a/Controller-afb/CMakeLists.txt +++ b/Controller-afb/CMakeLists.txt @@ -16,10 +16,24 @@ # limitations under the License. ########################################################################### -# Include LUA only when requested +ADD_COMPILE_OPTIONS(-DCONTROL_ONLOAD_DEFAULT="onload-default") + +ADD_COMPILE_OPTIONS(-DCONTROL_DOSCRIPT_PRE="doscript") +ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_PRE="onload") +ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_POST="control") +ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/config.d:${CMAKE_INSTALL_PREFIX}/controller/config.d") +ADD_COMPILE_OPTIONS(-DCTL_PLUGIN_MAGIC=2468013579) +ADD_COMPILE_OPTIONS(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}:${CMAKE_INSTALL_PREFIX}/controller/plugin:/usr/lib/afb/controller/ctlplug") + +# Include LUA only when requested if(CONTROL_SUPPORT_LUA) message(STATUS "Notice: LUA Controler Support Selected") set(CTL_LUA_SOURCE ctl-lua.c) + ADD_COMPILE_OPTIONS(-DCONTROL_SUPPORT_LUA) + ADD_COMPILE_OPTIONS(-DCONTROL_LUA_EVENT="luaevt") + ADD_COMPILE_OPTIONS(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controller/ctl-lua.d") +else(CONTROL_SUPPORT_LUA) + message(STATUS "Warning: LUA Without Support ") endif(CONTROL_SUPPORT_LUA) # Add target to project dependency list diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 9293781..e40bf7c 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -41,12 +41,6 @@ set(PROJECT_SRC_DIR_PATTERN "[^_]*") # ---------------------------------- set(CMAKE_BUILD_TYPE "DEBUG") -# Static constante definition -# ----------------------------- -add_compile_options(-DMAX_SND_CARD=16) # should be more than enough even in luxury vehicule -add_compile_options(-DMAX_LINEAR_DB_SCALE=24) # until 24db volume normalisation use a simple linear scale -add_compile_options(-DTLV_BYTE_SIZE=256) # Alsa use 4096 as default but 256 should fit most sndcards - # Compiler selection if needed. Overload the detected compiler. # ----------------------------------------------- set (gcc_minimal_version 4.9) @@ -65,37 +59,50 @@ set (PKG_REQUIRED_LIST lua>=5.3 ) +# Controller project needed variables. +# Compilation options specific to that target set +# in the CMakeLists.txt of that target to correctly +# expand variables. +# ---------------------------------------------------- +set(CONTROL_SUPPORT_LUA 1 CACHE BOOL "Active or not LUA Support") +set (CTL_PLUGIN_PRE "ctl-" CACHE STRING "Prefix for Controller share plugin") +set (CTL_PLUGIN_EXT ".ctlso" CACHE STRING "Postfix for Controller share plugin") + +# Compilation options definition +# Use CMake generator expressions to specify only for a specific language +# Values are prefilled with default options that is currently used. +# Either separate options with ";", or each options must be quoted separately +# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED ! +# ---------------------------------------------------------------------------- +set(COMPILE_OPTIONS +-Wall +-Wextra +-Wconversion +-Wno-unused-parameter +-Wno-sign-compare +-Wno-sign-conversion +-Werror=maybe-uninitialized +-Werror=implicit-function-declaration +-ffunction-sections +-fdata-sections +-fPIC +# Personal compilation options +-DMAX_SND_CARD=16 # should be more than enough even in luxury vehicule +-DMAX_LINEAR_DB_SCALE=24 # until 24db volume normalisation use a simple linear scale +-DTLV_BYTE_SIZE=256 # Alsa use 4096 as default but 256 should fit most sndcards +-DCONTROL_MAXPATH_LEN=255 + CACHE STRING "Compilation flags") +#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.") +#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.") +#set(PROFILING_COMPILE_OPTIONS -g -O0 -pg -Wp,-U_FORTIFY_SOURCE CACHE STRING "Compilation flags for PROFILING build type.") +#set(DEBUG_COMPILE_OPTIONS -g -ggdb -Wp,-U_FORTIFY_SOURCE CACHE STRING "Compilation flags for DEBUG build type.") +#set(CCOV_COMPILE_OPTIONS -g -O2 --coverage CACHE STRING "Compilation flags for CCOV build type.") +#set(RELEASE_COMPILE_OPTIONS -g -O2 CACHE STRING "Compilation flags for RELEASE build type.") -# Define CONTROL_CDEV_NAME should match MOST driver values -# --------------------------------------------------------- - add_compile_options(-DCONTROL_ONLOAD_DEFAULT="onload-default") - add_compile_options(-DCONTROL_MAXPATH_LEN=255) - add_compile_options(-DCONTROL_DOSCRIPT_PRE="doscript") - add_compile_options(-DCONTROL_CONFIG_PRE="onload") - add_compile_options(-DCONTROL_CONFIG_POST="control" ) - add_compile_options(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/config.d:${CMAKE_INSTALL_PREFIX}/controller/config.d") - - - set(CONTROL_SUPPORT_LUA 1 CACHE BOOL "Active or not LUA Support") - if(CONTROL_SUPPORT_LUA) - set(LUA_COMPILER "luac5.3" CACHE STRING "LUA syntaxe check") - add_compile_options(-DCONTROL_SUPPORT_LUA) - add_compile_options(-DCONTROL_LUA_EVENT="luaevt") - add_compile_options(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controller/ctl-lua.d") - else(CONTROL_SUPPORT_LUA) - message(STATUS "Warning: LUA Without Support ") - endif(CONTROL_SUPPORT_LUA) - - set (CTL_PLUGIN_PRE "ctl-" CACHE STRING "Prefix for Controller share plugin") - set (CTL_PLUGIN_EXT ".ctlso" CACHE STRING "Postfix for Controller share plugin") - add_compile_options(-DCTL_PLUGIN_MAGIC=2468013579) - add_compile_options(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}:${BINDINGS_INSTALL_DIR}/ctlplug:/usr/lib/afb/ctlplug") - # Print a helper message when every thing is finished # ---------------------------------------------------- set(CLOSING_MESSAGE "Debug in ./buid: afb-daemon --port=1234 --ldpaths=. --workdir=. --roothttp=../htdocs --tracereq=common --token='' --verbose") - # Optional dependencies order # --------------------------- #set(EXTRA_DEPENDENCIES_ORDER) -- cgit 1.2.3-korg From c07477e28bcb5e4d1a2774a51aaa0877059e7f11 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 18 Aug 2017 16:43:12 +0200 Subject: Remove BINDING_INSTALL_PREFIX/DIR variable Use CMAKE_INSTALL_PREFIX by default. Change-Id: I16f8018779b624842026ff401857e198c6436ddd Signed-off-by: Romain Forlot --- Alsa-afb/CMakeLists.txt | 2 +- Controller-afb/CMakeLists.txt | 8 ++++---- HAL-afb/HDA-intel/CMakeLists.txt | 2 +- HAL-afb/Jabra-Solemate/CMakeLists.txt | 2 +- HAL-afb/Scarlett-Focusrite/CMakeLists.txt | 2 +- conf.d/app-templates | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alsa-afb/CMakeLists.txt b/Alsa-afb/CMakeLists.txt index 876e837..38b957d 100644 --- a/Alsa-afb/CMakeLists.txt +++ b/Alsa-afb/CMakeLists.txt @@ -38,4 +38,4 @@ PROJECT_TARGET_ADD(alsa-lowlevel) # installation directory INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/Controller-afb/CMakeLists.txt b/Controller-afb/CMakeLists.txt index c128184..d1eb886 100644 --- a/Controller-afb/CMakeLists.txt +++ b/Controller-afb/CMakeLists.txt @@ -23,7 +23,7 @@ ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_PRE="onload") ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_POST="control") ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/config.d:${CMAKE_INSTALL_PREFIX}/controller/config.d") ADD_COMPILE_OPTIONS(-DCTL_PLUGIN_MAGIC=2468013579) -ADD_COMPILE_OPTIONS(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}:${CMAKE_INSTALL_PREFIX}/controller/plugin:/usr/lib/afb/controller/ctlplug") +ADD_COMPILE_OPTIONS(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}:${CMAKE_INSTALL_PREFIX}/controller-plugins:/usr/lib/afb/controller-plugins/ctlplug") # Include LUA only when requested if(CONTROL_SUPPORT_LUA) @@ -31,7 +31,7 @@ if(CONTROL_SUPPORT_LUA) set(CTL_LUA_SOURCE ctl-lua.c) ADD_COMPILE_OPTIONS(-DCONTROL_SUPPORT_LUA) ADD_COMPILE_OPTIONS(-DCONTROL_LUA_EVENT="luaevt") - ADD_COMPILE_OPTIONS(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controller/ctl-lua.d") + ADD_COMPILE_OPTIONS(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/controller-plugins/ctl-lua.d") else(CONTROL_SUPPORT_LUA) message(STATUS "Warning: LUA Without Support ") endif(CONTROL_SUPPORT_LUA) @@ -59,7 +59,7 @@ PROJECT_TARGET_ADD(control-afb) # installation directory INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION CMAKE_INSTALL_PREFIX ) + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX} ) PROJECT_TARGET_ADD(audio-plugin-sample) @@ -81,4 +81,4 @@ PROJECT_TARGET_ADD(audio-plugin-sample) # installation directory INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}/controler) + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/controler-plugins) diff --git a/HAL-afb/HDA-intel/CMakeLists.txt b/HAL-afb/HDA-intel/CMakeLists.txt index 37e277b..aa67e0b 100644 --- a/HAL-afb/HDA-intel/CMakeLists.txt +++ b/HAL-afb/HDA-intel/CMakeLists.txt @@ -39,4 +39,4 @@ PROJECT_TARGET_ADD(hal-intel-hda) # installation directory INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) \ No newline at end of file + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/HAL-afb/Jabra-Solemate/CMakeLists.txt b/HAL-afb/Jabra-Solemate/CMakeLists.txt index 973e95d..bf61dad 100644 --- a/HAL-afb/Jabra-Solemate/CMakeLists.txt +++ b/HAL-afb/Jabra-Solemate/CMakeLists.txt @@ -39,4 +39,4 @@ PROJECT_TARGET_ADD(hal-jabra-usb) # installation directory INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) \ No newline at end of file + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/HAL-afb/Scarlett-Focusrite/CMakeLists.txt b/HAL-afb/Scarlett-Focusrite/CMakeLists.txt index 48d5964..1cc83e6 100644 --- a/HAL-afb/Scarlett-Focusrite/CMakeLists.txt +++ b/HAL-afb/Scarlett-Focusrite/CMakeLists.txt @@ -39,4 +39,4 @@ PROJECT_TARGET_ADD(hal-scalett-usb) # installation directory INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) \ No newline at end of file + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/conf.d/app-templates b/conf.d/app-templates index aa763dd..90f7727 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit aa763ddec685dc44bcb5d44718d78f3692d4f0dc +Subproject commit 90f7727a83baa15701e3ad1a83cb12a14346b13b -- cgit 1.2.3-korg From 7d3aa94e8be267a166caf4e2c6f29529aa4cabbd Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 18 Aug 2017 17:52:21 +0200 Subject: Added default variables from sample Change-Id: I9170f9834868035ab76faaaae941f2c5decf589d Signed-off-by: Romain Forlot --- conf.d/cmake/config.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index e40bf7c..b5e3a4c 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -102,6 +102,12 @@ set(COMPILE_OPTIONS # Print a helper message when every thing is finished # ---------------------------------------------------- set(CLOSING_MESSAGE "Debug in ./buid: afb-daemon --port=1234 --ldpaths=. --workdir=. --roothttp=../htdocs --tracereq=common --token='' --verbose") +#set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") + +# Optional location for config.xml.in +# ----------------------------------- +#set(WIDGET_ICON conf.d/wgt/${PROJECT_ICON} CACHE PATH "Path to the widget icon") +#set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in CACHE PATH "Path to widget config file template (config.xml.in)") # Optional dependencies order # --------------------------- -- cgit 1.2.3-korg From c58b7ea33694ab8c76f8cb452d3b8928eb3279ad Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Fri, 18 Aug 2017 17:53:48 +0200 Subject: Fix widget build, using icon/config specified Change-Id: I8f1adc76a35553a7c3cf22f996aba3a21bd096f6 Signed-off-by: Romain Forlot --- conf.d/app-templates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.d/app-templates b/conf.d/app-templates index 90f7727..9a73785 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 90f7727a83baa15701e3ad1a83cb12a14346b13b +Subproject commit 9a737858056dae3348e4659ed5e9168d39f1b23a -- cgit 1.2.3-korg From d51d083be8e34000cd00ce979445eacb45a16e97 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Sun, 20 Aug 2017 17:16:28 +0200 Subject: Updated to latest App Template --- Alsa-afb/Alsa-ApiHat.c | 2 +- Alsa-afb/CMakeLists.txt | 3 - Audio-Common/filescan-utils.c | 9 +- Controller-afb/CMakeLists.txt | 5 +- Controller-afb/README.md | 2 +- Controller-afb/ctl-binding.c | 7 +- Controller-afb/ctl-dispatch.c | 4 +- Controller-afb/ctl-lua.c | 7 +- HAL-afb/HDA-intel/CMakeLists.txt | 3 - HAL-afb/Jabra-Solemate/CMakeLists.txt | 4 - HAL-afb/Scarlett-Focusrite/CMakeLists.txt | 4 - README.md | 4 +- conf.d/app-templates | 2 +- conf.d/project/config.d/CMakeLists.txt | 32 - conf.d/project/config.d/onload-audio-control.json | 128 ---- .../project/config.d/onload-daemon-standalone.json | 72 -- conf.d/project/json.d/CMakeLists.txt | 32 + conf.d/project/json.d/onload-audio-control.json | 128 ++++ .../project/json.d/onload-daemon-standalone.json | 72 ++ conf.d/project/lua.d/onload-aaaa-00-utils.lua | 86 +++ conf.d/project/lua.d/onload-aaaa-01-controls.lua | 162 +++++ conf.d/project/lua.d/onload-aaaa-02-timer.lua | 69 ++ conf.d/project/lua.d/onload-aaaa-03-oncall.lua | 70 ++ conf.d/project/lua.d/onload-audio-0utils.lua | 86 --- conf.d/project/lua.d/onload-audio-controls.lua | 162 ----- conf.d/project/lua.d/onload-audio-oncall.lua | 70 -- conf.d/project/lua.d/onload-audio-timer.lua | 69 -- data/CMakeLists.txt | 33 - data/default-control-policy.json | 90 --- nbproject/configurations.xml | 759 +++++++++++++++++++-- nbproject/project.xml | 4 + 31 files changed, 1339 insertions(+), 841 deletions(-) delete mode 100644 conf.d/project/config.d/CMakeLists.txt delete mode 100644 conf.d/project/config.d/onload-audio-control.json delete mode 100644 conf.d/project/config.d/onload-daemon-standalone.json create mode 100644 conf.d/project/json.d/CMakeLists.txt create mode 100644 conf.d/project/json.d/onload-audio-control.json create mode 100644 conf.d/project/json.d/onload-daemon-standalone.json create mode 100644 conf.d/project/lua.d/onload-aaaa-00-utils.lua create mode 100644 conf.d/project/lua.d/onload-aaaa-01-controls.lua create mode 100644 conf.d/project/lua.d/onload-aaaa-02-timer.lua create mode 100644 conf.d/project/lua.d/onload-aaaa-03-oncall.lua delete mode 100644 conf.d/project/lua.d/onload-audio-0utils.lua delete mode 100644 conf.d/project/lua.d/onload-audio-controls.lua delete mode 100644 conf.d/project/lua.d/onload-audio-oncall.lua delete mode 100644 conf.d/project/lua.d/onload-audio-timer.lua delete mode 100644 data/CMakeLists.txt delete mode 100644 data/default-control-policy.json diff --git a/Alsa-afb/Alsa-ApiHat.c b/Alsa-afb/Alsa-ApiHat.c index a8663ca..e22f2d5 100644 --- a/Alsa-afb/Alsa-ApiHat.c +++ b/Alsa-afb/Alsa-ApiHat.c @@ -31,7 +31,7 @@ #include "Alsa-ApiHat.h" STATIC int AlsaInit(void) { - int rc= prctl(PR_SET_NAME, "afb-audio-agent",NULL,NULL,NULL); + int rc= prctl(PR_SET_NAME, "afb-aaaa-agent",NULL,NULL,NULL); if (rc) AFB_ERROR("ERROR: AlsaCore fail to rename process"); return rc; diff --git a/Alsa-afb/CMakeLists.txt b/Alsa-afb/CMakeLists.txt index 38b957d..fab49ae 100644 --- a/Alsa-afb/CMakeLists.txt +++ b/Alsa-afb/CMakeLists.txt @@ -36,6 +36,3 @@ PROJECT_TARGET_ADD(alsa-lowlevel) ${link_libraries} ) - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/Audio-Common/filescan-utils.c b/Audio-Common/filescan-utils.c index af0b5c9..4a5613f 100644 --- a/Audio-Common/filescan-utils.c +++ b/Audio-Common/filescan-utils.c @@ -113,9 +113,12 @@ PUBLIC const char *GetBinderName() { if (binderName) return binderName; - // retrieve binder name from process name afb-name-trailer - prctl(PR_GET_NAME, psName,NULL,NULL,NULL); - binderName=(char*)GetMidleName(psName); + binderName= getenv("AFB_BINDER_NAME"); + if (!binderName) { + // retrieve binder name from process name afb-name-trailer + prctl(PR_GET_NAME, psName,NULL,NULL,NULL); + binderName=(char*)GetMidleName(psName); + } return binderName; } \ No newline at end of file diff --git a/Controller-afb/CMakeLists.txt b/Controller-afb/CMakeLists.txt index d1eb886..c7602f8 100644 --- a/Controller-afb/CMakeLists.txt +++ b/Controller-afb/CMakeLists.txt @@ -16,7 +16,7 @@ # limitations under the License. ########################################################################### -ADD_COMPILE_OPTIONS(-DCONTROL_ONLOAD_DEFAULT="onload-default") +ADD_COMPILE_OPTIONS(-DCONTROL_ONLOAD_PROFILE="onload-default-profile") ADD_COMPILE_OPTIONS(-DCONTROL_DOSCRIPT_PRE="doscript") ADD_COMPILE_OPTIONS(-DCONTROL_CONFIG_PRE="onload") @@ -57,9 +57,6 @@ PROJECT_TARGET_ADD(control-afb) ${link_libraries} ) - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX} ) PROJECT_TARGET_ADD(audio-plugin-sample) diff --git a/Controller-afb/README.md b/Controller-afb/README.md index e6cab72..9bab485 100644 --- a/Controller-afb/README.md +++ b/Controller-afb/README.md @@ -30,7 +30,7 @@ Each bloc in the configuration file are defined with * info: optional used for documentation purpose only Note by default controller config search path is defined at compilation time, but path might be overloaded with CONTROL_CONFIG_PATH -environment variable. +environment variable. Setenv 'CONTROL_ONLOAD_PROFILE'=xxxx to overload 'onload-default-profile' initialisation sequence. ### Config is organised in 4 sections: diff --git a/Controller-afb/ctl-binding.c b/Controller-afb/ctl-binding.c index 8771fc0..ec33f82 100644 --- a/Controller-afb/ctl-binding.c +++ b/Controller-afb/ctl-binding.c @@ -55,9 +55,12 @@ PUBLIC int CtlBindingInit () { errcount += LuaLibInit(); #endif + const char *profile= getenv("CONTROL_ONLOAD_PROFILE"); + if (!profile) profile=CONTROL_ONLOAD_PROFILE; + // now that everything is initialised execute the onload action - if (!errcount) - errcount += DispatchOnLoad(CONTROL_ONLOAD_DEFAULT); + if (!errcount) + errcount += DispatchOnLoad(CONTROL_ONLOAD_PROFILE); AFB_DEBUG ("Audio Policy Control Binding Done errcount=%d", errcount); return errcount; diff --git a/Controller-afb/ctl-dispatch.c b/Controller-afb/ctl-dispatch.c index 1708204..0104229 100644 --- a/Controller-afb/ctl-dispatch.c +++ b/Controller-afb/ctl-dispatch.c @@ -178,6 +178,8 @@ PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ) { // Event name is mapped on control label and executed as a standard control PUBLIC int DispatchOnLoad(const char *onLoadLabel) { + if (!configHandle) return 1; + DispatchHandleT **onloads = configHandle->onloads; int err = DispatchOneControl(CTL_SOURCE_ONLOAD, onloads, onLoadLabel, NULL, NULL_AFBREQ); @@ -650,7 +652,7 @@ PUBLIC int DispatchInit() { // no dispatch config found remove control API from binder if (!luaLoaded) { - AFB_WARNING("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile); + AFB_WARNING("DISPATCH-INIT:WARNING (setenv CONTROL_CONFIG_PATH) No Config '%s-*.json' in '%s'", controlFile, dirList); } AFB_NOTICE("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init"); diff --git a/Controller-afb/ctl-lua.c b/Controller-afb/ctl-lua.c index 4ef6b65..3f45055 100644 --- a/Controller-afb/ctl-lua.c +++ b/Controller-afb/ctl-lua.c @@ -965,7 +965,10 @@ PUBLIC int LuaLibInit () { strncat (fullprefix, GetBinderName(), sizeof(fullprefix)); strncat (fullprefix, "-", sizeof(fullprefix)); - json_object *luaScriptPathJ = ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, fullprefix, "lua"); + const char *dirList= getenv("CONTROL_LUA_PATH"); + if (!dirList) dirList=CONTROL_LUA_PATH; + + json_object *luaScriptPathJ = ScanForConfig(dirList , CTL_SCAN_RECURSIVE, fullprefix, "lua"); // open a new LUA interpretor luaState = luaL_newstate(); @@ -1021,7 +1024,7 @@ PUBLIC int LuaLibInit () { // no policy config found remove control API from binder if (index == 0) { - AFB_WARNING ("POLICY-INIT:WARNING No Control LUA file in path=[%s]", CONTROL_LUA_PATH); + AFB_WARNING ("POLICY-INIT:WARNING (setenv CONTROL_LUA_PATH) No LUA '%s*.lua' in '%s'", fullprefix, dirList); } AFB_DEBUG ("Audio control-LUA Init Done"); diff --git a/HAL-afb/HDA-intel/CMakeLists.txt b/HAL-afb/HDA-intel/CMakeLists.txt index aa67e0b..380e493 100644 --- a/HAL-afb/HDA-intel/CMakeLists.txt +++ b/HAL-afb/HDA-intel/CMakeLists.txt @@ -37,6 +37,3 @@ PROJECT_TARGET_ADD(hal-intel-hda) audio-common ) - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/HAL-afb/Jabra-Solemate/CMakeLists.txt b/HAL-afb/Jabra-Solemate/CMakeLists.txt index bf61dad..41d6915 100644 --- a/HAL-afb/Jabra-Solemate/CMakeLists.txt +++ b/HAL-afb/Jabra-Solemate/CMakeLists.txt @@ -36,7 +36,3 @@ PROJECT_TARGET_ADD(hal-jabra-usb) hal-interface audio-common ) - - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/HAL-afb/Scarlett-Focusrite/CMakeLists.txt b/HAL-afb/Scarlett-Focusrite/CMakeLists.txt index 1cc83e6..90ee92a 100644 --- a/HAL-afb/Scarlett-Focusrite/CMakeLists.txt +++ b/HAL-afb/Scarlett-Focusrite/CMakeLists.txt @@ -36,7 +36,3 @@ PROJECT_TARGET_ADD(hal-scalett-usb) hal-interface audio-common ) - - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/README.md b/README.md index 2063677..e9ad55f 100644 --- a/README.md +++ b/README.md @@ -113,9 +113,7 @@ from the wrong relative directory, either you have to use 'set solib-search-path # ToBeBone (WorkInProgess: This list is getting longer every day) ------------------------------------------------------------------- -* Support response from LUA with nested table (currently fail miserably) -* Add timer base callback from Lua -* Enable export of LUA commands directly from Plugin + * Allow LUA to run a shell command # Running an debugging on a target ------------------------------------------------------- diff --git a/conf.d/app-templates b/conf.d/app-templates index 9a73785..350c5b9 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 9a737858056dae3348e4659ed5e9168d39f1b23a +Subproject commit 350c5b97459226f7e031c73edb3a79a2d99cb250 diff --git a/conf.d/project/config.d/CMakeLists.txt b/conf.d/project/config.d/CMakeLists.txt deleted file mode 100644 index 8070997..0000000 --- a/conf.d/project/config.d/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -########################################################################### -# Copyright 2017 IoT.bzh -# -# author: Fulup Ar Foll -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -########################################################################### - - -################################################## -# Control Policy Config file -################################################## -PROJECT_TARGET_ADD(ctl-config.d) - - file(GLOB XML_FILES "*.json") - - add_input_files("${XML_FILES}") - - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - LABELS "DATA" - OUTPUT_NAME ${TARGET_NAME} - ) diff --git a/conf.d/project/config.d/onload-audio-control.json b/conf.d/project/config.d/onload-audio-control.json deleted file mode 100644 index 77a8fce..0000000 --- a/conf.d/project/config.d/onload-audio-control.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "$schema": "ToBeDone", - "metadata": { - "label": "sample-audio-control", - "info": "Provide Default Audio Policy for Multimedia, Navigation and Emergency", - "version": "1.0" - }, - "onload": [{ - "label": "onload-default", - "info": "onload initialisation config", - "plugin": { - "label" : "_MyPlug", - "sharelib": "ctl-audio-plugin-sample.ctlso", - "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] - }, - "require": ["intel-hda", "jabra-usb", "scarlett-usb"], - "actions": [ - { - "label": "onload-sample-cb", - "info": "Call control sharelib install entrypoint", - "callback": "SamplePolicyInit", - "args": { - "arg1": "first_arg", - "nextarg": "second arg value" - } - }, { - "label": "onload-sample-api", - "info": "Assert AlsaCore Presence", - "api": "alsacore", - "verb": "ping", - "args": {"data": "none"} - }, { - "label": "onload-hal-lua", - "info": "Load avaliable HALs", - "lua": "_Alsa_Get_Hal" - } - ] - }], - "controls": - [ - { - "label": "multimedia", - "actions": { - "label": "multimedia-control-lua", - "info": "Call Lua Script function Test_Lua_Engin", - "lua": "_Audio_Set_Multimedia" - } - }, { - "label": "navigation", - "actions": { - "label": "navigation-control-lua", - "info": "Call Lua Script to set Navigation", - "lua": "_Audio_Set_Navigation" - } - }, { - "label": "emergency", - "actions": { - "label": "emergency-control-ucm", - "lua": "_Audio_Set_Emergency" - } - }, { - "label": "multi-step-sample", - "info" : "all actions must succeed for control to be accepted", - "actions": [{ - "label": "multimedia-control-cb", - "info": "Call Sharelib Sample Callback", - "callback": "sampleControlNavigation", - "args": { - "arg1": "snoopy", - "arg2": "toto" - } - }, { - "label": "navigation-control-ucm", - "api": "alsacore", - "verb": "ping", - "args": { - "test": "navigation" - } - }, { - "label": "navigation-control-lua", - "info": "Call Lua Script to set Navigation", - "lua": "_Audio_Set_Navigation" - }] - } - ], - "events": - [ - { - "label": "SampleEvent1", - "info": "define action when receiving a given event", - "actions": [ - { - "label": "Event Callback-1", - "callback": "SampleControlEvent", - "args": { - "arg": "action-1" - } - }, { - "label": "Event Callback-2", - "callback": "SampleControlEvent", - "args": { - "arg": "action-2" - } - } - ] - }, - { - "label": "SampleEvent2", - "info": "define action when receiving a given event", - "actions": [ - { - "label": "Event Callback-1", - "callback": "SampleControlEvent", - "args": { - "arg": "action-1" - } - }, { - "label": "Event Callback-2", - "callback": "SampleControlEvent", - "args": { - "arg": "action-2" - } - } - ] - } - ] -} - diff --git a/conf.d/project/config.d/onload-daemon-standalone.json b/conf.d/project/config.d/onload-daemon-standalone.json deleted file mode 100644 index de52c22..0000000 --- a/conf.d/project/config.d/onload-daemon-standalone.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "$schema": "ToBeDone", - "metadata": { - "label": "sample-standalone-control", - "info": "Minimal Standalone Controller Config", - "version": "1.0" - }, - "onload": [{ - "label": "onload-default", - "info": "onload initialisation config", - "actions": - { - "label": "control-init", - "lua": "_Control_Init" - } - }], - "controls": - [ - { - "label": "Button-1", - "actions": { - "label": "Action on Button One", - "lua": "_Button_Press", - "args": { - "button": 1 - } - } - }, { - "label": "Button-1", - "actions": { - "label": "Action on Button Two", - "lua": "_Button_Press", - "args": { - "button": 2 - } - } - }, { - "label": "Button-1", - "actions": { - "label": "Action on Button Three", - "lua": "_Button_Press", - "args": { - "button": 3 - } - } - } - ], - "events": - [ - { - "label": "Event1", - "actions": { - "label": "Action Event 1", - "lua": "_Event_Received", - "args": { - "evtname": "xxx" - } - } - }, - { - "label": "Event2", - "actions": { - "label": "Action Event 2", - "lua": "_Event_Received", - "args": { - "evtname": "yyy" - } - } - } - ] -} - diff --git a/conf.d/project/json.d/CMakeLists.txt b/conf.d/project/json.d/CMakeLists.txt new file mode 100644 index 0000000..8070997 --- /dev/null +++ b/conf.d/project/json.d/CMakeLists.txt @@ -0,0 +1,32 @@ +########################################################################### +# Copyright 2017 IoT.bzh +# +# author: Fulup Ar Foll +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################### + + +################################################## +# Control Policy Config file +################################################## +PROJECT_TARGET_ADD(ctl-config.d) + + file(GLOB XML_FILES "*.json") + + add_input_files("${XML_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "DATA" + OUTPUT_NAME ${TARGET_NAME} + ) diff --git a/conf.d/project/json.d/onload-audio-control.json b/conf.d/project/json.d/onload-audio-control.json new file mode 100644 index 0000000..77a8fce --- /dev/null +++ b/conf.d/project/json.d/onload-audio-control.json @@ -0,0 +1,128 @@ +{ + "$schema": "ToBeDone", + "metadata": { + "label": "sample-audio-control", + "info": "Provide Default Audio Policy for Multimedia, Navigation and Emergency", + "version": "1.0" + }, + "onload": [{ + "label": "onload-default", + "info": "onload initialisation config", + "plugin": { + "label" : "_MyPlug", + "sharelib": "ctl-audio-plugin-sample.ctlso", + "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"] + }, + "require": ["intel-hda", "jabra-usb", "scarlett-usb"], + "actions": [ + { + "label": "onload-sample-cb", + "info": "Call control sharelib install entrypoint", + "callback": "SamplePolicyInit", + "args": { + "arg1": "first_arg", + "nextarg": "second arg value" + } + }, { + "label": "onload-sample-api", + "info": "Assert AlsaCore Presence", + "api": "alsacore", + "verb": "ping", + "args": {"data": "none"} + }, { + "label": "onload-hal-lua", + "info": "Load avaliable HALs", + "lua": "_Alsa_Get_Hal" + } + ] + }], + "controls": + [ + { + "label": "multimedia", + "actions": { + "label": "multimedia-control-lua", + "info": "Call Lua Script function Test_Lua_Engin", + "lua": "_Audio_Set_Multimedia" + } + }, { + "label": "navigation", + "actions": { + "label": "navigation-control-lua", + "info": "Call Lua Script to set Navigation", + "lua": "_Audio_Set_Navigation" + } + }, { + "label": "emergency", + "actions": { + "label": "emergency-control-ucm", + "lua": "_Audio_Set_Emergency" + } + }, { + "label": "multi-step-sample", + "info" : "all actions must succeed for control to be accepted", + "actions": [{ + "label": "multimedia-control-cb", + "info": "Call Sharelib Sample Callback", + "callback": "sampleControlNavigation", + "args": { + "arg1": "snoopy", + "arg2": "toto" + } + }, { + "label": "navigation-control-ucm", + "api": "alsacore", + "verb": "ping", + "args": { + "test": "navigation" + } + }, { + "label": "navigation-control-lua", + "info": "Call Lua Script to set Navigation", + "lua": "_Audio_Set_Navigation" + }] + } + ], + "events": + [ + { + "label": "SampleEvent1", + "info": "define action when receiving a given event", + "actions": [ + { + "label": "Event Callback-1", + "callback": "SampleControlEvent", + "args": { + "arg": "action-1" + } + }, { + "label": "Event Callback-2", + "callback": "SampleControlEvent", + "args": { + "arg": "action-2" + } + } + ] + }, + { + "label": "SampleEvent2", + "info": "define action when receiving a given event", + "actions": [ + { + "label": "Event Callback-1", + "callback": "SampleControlEvent", + "args": { + "arg": "action-1" + } + }, { + "label": "Event Callback-2", + "callback": "SampleControlEvent", + "args": { + "arg": "action-2" + } + } + ] + } + ] +} + diff --git a/conf.d/project/json.d/onload-daemon-standalone.json b/conf.d/project/json.d/onload-daemon-standalone.json new file mode 100644 index 0000000..de52c22 --- /dev/null +++ b/conf.d/project/json.d/onload-daemon-standalone.json @@ -0,0 +1,72 @@ +{ + "$schema": "ToBeDone", + "metadata": { + "label": "sample-standalone-control", + "info": "Minimal Standalone Controller Config", + "version": "1.0" + }, + "onload": [{ + "label": "onload-default", + "info": "onload initialisation config", + "actions": + { + "label": "control-init", + "lua": "_Control_Init" + } + }], + "controls": + [ + { + "label": "Button-1", + "actions": { + "label": "Action on Button One", + "lua": "_Button_Press", + "args": { + "button": 1 + } + } + }, { + "label": "Button-1", + "actions": { + "label": "Action on Button Two", + "lua": "_Button_Press", + "args": { + "button": 2 + } + } + }, { + "label": "Button-1", + "actions": { + "label": "Action on Button Three", + "lua": "_Button_Press", + "args": { + "button": 3 + } + } + } + ], + "events": + [ + { + "label": "Event1", + "actions": { + "label": "Action Event 1", + "lua": "_Event_Received", + "args": { + "evtname": "xxx" + } + } + }, + { + "label": "Event2", + "actions": { + "label": "Action Event 2", + "lua": "_Event_Received", + "args": { + "evtname": "yyy" + } + } + } + ] +} + diff --git a/conf.d/project/lua.d/onload-aaaa-00-utils.lua b/conf.d/project/lua.d/onload-aaaa-00-utils.lua new file mode 100644 index 0000000..b8ecd7e --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-00-utils.lua @@ -0,0 +1,86 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Note: this file should be called before any other to assert declare function + is loaded before anything else. + + References: + http://lua-users.org/wiki/DetectingUndefinedVariables + +--]] + + +--=================================================== +--= Niklas Frykholm +-- basically if user tries to create global variable +-- the system will not let them!! +-- call GLOBAL_lock(_G) +-- +--=================================================== +function GLOBAL_lock(t) + local mt = getmetatable(t) or {} + mt.__newindex = lock_new_index + setmetatable(t, mt) +end + +--=================================================== +-- call GLOBAL_unlock(_G) +-- to change things back to normal. +--=================================================== +function GLOBAL_unlock(t) + local mt = getmetatable(t) or {} + mt.__newindex = unlock_new_index + setmetatable(t, mt) +end + +function lock_new_index(t, k, v) + if (string.sub(k,1,1) ~= "_") then + GLOBAL_unlock(_G) + error("GLOBALS are locked -- " .. k .. + " must be declared local or prefix with '_' for globals.", 2) + else + rawset(t, k, v) + end +end + +function unlock_new_index(t, k, v) + rawset(t, k, v) +end + +-- return serialised version of printable table +function Dump_Table(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. Dump_Table(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + + +-- simulate C prinf function +printf = function(s,...) + io.write(s:format(...)) + io.write("\n") + return +end + +-- lock global variable +GLOBAL_lock(_G) diff --git a/conf.d/project/lua.d/onload-aaaa-01-controls.lua b/conf.d/project/lua.d/onload-aaaa-01-controls.lua new file mode 100644 index 0000000..24c4f71 --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-01-controls.lua @@ -0,0 +1,162 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Provide sample policy function for AGL Advance Audio Agent +--]] + +-- Global HAL registry +_Audio_Hal_Registry={} + +-- Callback when receiving HAL registry +function _Alsa_Get_Hal_CB (error, result, context) + -- Initialise an empty table + local registry={} + + -- Only process when response is valid + if (error) then + AFB_ErrOr ("[Audio_Init_CB] ErrOr result=%s", result) + return + end + + -- Extract response from result + local response=result["response"] + + -- Index HAL Bindings APIs by shortname + for key,value in pairs(response) do + registry[value["shortname"]]=value["api"] + end + + -- store Exiting HAL for further use + printf ("-- [Audio_Init_CB] -- Audio_register_Hal=%s", Dump_Table(registry)) + _Audio_Hal_Registry=registry + +end + +-- Function call at binding load time +function _Alsa_Get_Hal(args) + + printf ("[-- Audio_Get_Hal --] args=%s", Dump_Table(argsT)) + + -- Query AlsaCore for Active HALs (no query, no context) + AFB:service ('alsacore', 'hallist', {}, "_Alsa_Get_Hal_CB", {}) + +end + +-- In sample configuration Query/Args parsing is common to all audio control +local function Audio_Parse_Request (source, args, query) + + local apihal={} + + -- In this test we expect targeted device to be given from query (could come for args as well) + if (query == nil ) then + AFB:error ("--LUA:Audio_Set_Navigation query should contain and args with targeted apihal|device") + return -- refuse control + end + + -- Alsa Hook plugin asound sample config provides target sound card by name + if (query["device"] ~= nil) then + apihal=_Audio_Hal_Registry[query["device"]] + end + + -- HTML5 test page provides directly HAL api. + if (query["apihal"] ~= nil) then + apihal= query["apihal"] + end + + -- if requested HAL is not found then deny the control + if (apihal == nil) then + AFB:error ("--LUA:Audio_Set_Navigation No Active HAL Found") + return -- refuse control + end + + -- return api or nil when not found + return apihal +end + +-- Set Navigation lower sound when play +function _Audio_Set_Navigation(source, args, query) + + -- in strict mode every variables should be declared + local err=0 + local ctlhal={} + local response={} + local apihal={} + + AFB:notice ("LUA:Audio_Set_Use_Case source=%d args=%s query=%s", source, args, query); + + -- Parse Query/Args and if HAL not found then refuse access + apihal= Audio_Parse_Request (source, args, query) + if (apihal == nil) then return 1 end + + + -- if source < 0 then Alsa HookPlugin is closing PCM + if (source < 0) then + -- Ramp Up Multimedia channel synchronously + ctlhal={['label']='Master_Playback_Volume', ['val']=100} + err, response= AFB:servsync (apihal, 'ctlset',ctlhal) + else + -- Ramp Down Multimedia channel synchronously + ctlhal={['label']='Master_Playback_Volume', ['val']=50} + err, response= AFB:servsync (apihal, 'ctlset',ctlhal) + end + + if (err) then + AFB:error("--LUA:Audio_Set_Navigation halapi=%s refuse ctl=%s", apihal, ctlhal) + return 1 -- control refused + end + + + return 0 -- control accepted +end + + +-- Select Multimedia mode +function _Audio_Set_Multimedia (source, args, query) + + -- in strict mode every variables should be declared + local err=0 + local ctlhal={} + local response={} + local apihal={} + + AFB:notice ("LUA:Audio_Set_Use_Case source=%d args=%s query=%s", source, args, query); + + -- Parse Query/Args and if HAL not found then refuse access + apihal= Audio_Parse_Request (source, args, query) + if (apihal == nil) then return 1 end + + + -- if Mumtimedia control only increase volume on open + if (source >= 0) then + -- Ramp Down Multimedia channel synchronously + ctlhal={['label']='Master_Playback_Volume', ['val']=100} + err, response= AFB:servsync (apihal, 'ctlset',ctlhal) + end + + if (err) then + AFB:error("--LUA:Audio_Set_Navigation halapi=%s refuse ctl=%s", apihal, ctlhal) + return 1 -- control refused + end + + + return 0 -- control accepted +end + +-- Select Emergency Mode +function _Audio_Set_Emergency(source, args, query) + return 1 -- Always refuse in this test +end diff --git a/conf.d/project/lua.d/onload-aaaa-02-timer.lua b/conf.d/project/lua.d/onload-aaaa-02-timer.lua new file mode 100644 index 0000000..db7a937 --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-02-timer.lua @@ -0,0 +1,69 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Provide Sample Timer Handing to push event from LUA +--]] + +-- Create event on Lua script load +local MyEventHandle=AFB:evtmake("MyTestEvent") + +-- Call count time every delay/ms +local function Timer_Test_CB (timer, context) + + local evtinfo= AFB:timerget(timer) + print ("timer=", Dump_Table(evtinfo)) + + --send an event an event with count as value + AFB:evtpush (MyEventHandle, {["label"]= evtinfo["label"], ["count"]=evtinfo["count"], ["info"]=context["info"]}) + + -- note when timerCB return!=0 timer is kill + return 0 + +end + +-- sendback event depending on count and delay +function _Simple_Timer_Test (request, args) + + local context = { + ["info"]="My 1st private Event", + } + + -- if delay not defined default is 5s + if (args["delay"]==nil) then args["delay"]=5000 end + + -- if count is not defined default is 10 + if (args["count"]==nil) then args["count"]=10 end + + -- we could use directly args but it is a sample + local myTimer = { + ["label"]=args["label"], + ["delay"]=args["delay"], + ["count"]=args["count"], + } + AFB:notice ("Test_Timer myTimer=%s", myTimer) + + -- subscribe to event + AFB:subscribe (request, MyEventHandle) + + -- settimer take a table with delay+count as input (count==0 means infinite) + AFB:timerset (myTimer, "Timer_Test_CB", context) + + -- nothing special to return send back args + AFB:success (request, myTimer) + + return 0 +end diff --git a/conf.d/project/lua.d/onload-aaaa-03-oncall.lua b/conf.d/project/lua.d/onload-aaaa-03-oncall.lua new file mode 100644 index 0000000..23b538e --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-03-oncall.lua @@ -0,0 +1,70 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Provide sample LUA routines to be used with AGL control "lua_docall" API +--]] + +--global counter to keep track of calls +_count=0 + +-- Display receive arguments and echo them to caller +function _Simple_Echo_Args (request, args) + _count=_count+1 + AFB:notice("LUA OnCall Echo Args count=%d args=%s", count, args) + + print ("--inlua-- args=", Dump_Table(args)) + + local response={ + ["count"]=_count, + ["args"]=args, + } + + -- fulup Embdeded table ToeDone AFB:success (request, response) + AFB:success (request, {["func"]="Simple_Echo_Args", ["ret1"]=5678, ["ret2"]="abcd"}) +end + +local function Test_Async_CB (request, result, context) + response={ + ["result"]=result, + ["context"]=context, + } + + AFB:notice ("Test_Async_CB result=%s context=%s", result, context) + AFB:success (request, response) +end + +function _Test_Call_Async (request, args) + local context={ + ["value1"]="abcd", + ["value2"]=1234 + } + + AFB:notice ("Test_Call_Async args=%s cb=Test_Async_CB", args) + AFB:service("alsacore","ping", "Test_Async_CB", context) +end + +function _Test_Call_Sync (request, args) + + AFB:notice ("Test_Call_Sync args=%s", args) + local err, response= AFB:service_sync ("alsacore","ping", args) + if (err) then + AFB:fail ("AFB:service_call_sync fail"); + else + AFB:success (request, response) + end +end + diff --git a/conf.d/project/lua.d/onload-audio-0utils.lua b/conf.d/project/lua.d/onload-audio-0utils.lua deleted file mode 100644 index b8ecd7e..0000000 --- a/conf.d/project/lua.d/onload-audio-0utils.lua +++ /dev/null @@ -1,86 +0,0 @@ ---[[ - Copyright (C) 2016 "IoT.bzh" - Author Fulup Ar Foll - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Note: this file should be called before any other to assert declare function - is loaded before anything else. - - References: - http://lua-users.org/wiki/DetectingUndefinedVariables - ---]] - - ---=================================================== ---= Niklas Frykholm --- basically if user tries to create global variable --- the system will not let them!! --- call GLOBAL_lock(_G) --- ---=================================================== -function GLOBAL_lock(t) - local mt = getmetatable(t) or {} - mt.__newindex = lock_new_index - setmetatable(t, mt) -end - ---=================================================== --- call GLOBAL_unlock(_G) --- to change things back to normal. ---=================================================== -function GLOBAL_unlock(t) - local mt = getmetatable(t) or {} - mt.__newindex = unlock_new_index - setmetatable(t, mt) -end - -function lock_new_index(t, k, v) - if (string.sub(k,1,1) ~= "_") then - GLOBAL_unlock(_G) - error("GLOBALS are locked -- " .. k .. - " must be declared local or prefix with '_' for globals.", 2) - else - rawset(t, k, v) - end -end - -function unlock_new_index(t, k, v) - rawset(t, k, v) -end - --- return serialised version of printable table -function Dump_Table(o) - if type(o) == 'table' then - local s = '{ ' - for k,v in pairs(o) do - if type(k) ~= 'number' then k = '"'..k..'"' end - s = s .. '['..k..'] = ' .. Dump_Table(v) .. ',' - end - return s .. '} ' - else - return tostring(o) - end -end - - --- simulate C prinf function -printf = function(s,...) - io.write(s:format(...)) - io.write("\n") - return -end - --- lock global variable -GLOBAL_lock(_G) diff --git a/conf.d/project/lua.d/onload-audio-controls.lua b/conf.d/project/lua.d/onload-audio-controls.lua deleted file mode 100644 index 24c4f71..0000000 --- a/conf.d/project/lua.d/onload-audio-controls.lua +++ /dev/null @@ -1,162 +0,0 @@ ---[[ - Copyright (C) 2016 "IoT.bzh" - Author Fulup Ar Foll - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Provide sample policy function for AGL Advance Audio Agent ---]] - --- Global HAL registry -_Audio_Hal_Registry={} - --- Callback when receiving HAL registry -function _Alsa_Get_Hal_CB (error, result, context) - -- Initialise an empty table - local registry={} - - -- Only process when response is valid - if (error) then - AFB_ErrOr ("[Audio_Init_CB] ErrOr result=%s", result) - return - end - - -- Extract response from result - local response=result["response"] - - -- Index HAL Bindings APIs by shortname - for key,value in pairs(response) do - registry[value["shortname"]]=value["api"] - end - - -- store Exiting HAL for further use - printf ("-- [Audio_Init_CB] -- Audio_register_Hal=%s", Dump_Table(registry)) - _Audio_Hal_Registry=registry - -end - --- Function call at binding load time -function _Alsa_Get_Hal(args) - - printf ("[-- Audio_Get_Hal --] args=%s", Dump_Table(argsT)) - - -- Query AlsaCore for Active HALs (no query, no context) - AFB:service ('alsacore', 'hallist', {}, "_Alsa_Get_Hal_CB", {}) - -end - --- In sample configuration Query/Args parsing is common to all audio control -local function Audio_Parse_Request (source, args, query) - - local apihal={} - - -- In this test we expect targeted device to be given from query (could come for args as well) - if (query == nil ) then - AFB:error ("--LUA:Audio_Set_Navigation query should contain and args with targeted apihal|device") - return -- refuse control - end - - -- Alsa Hook plugin asound sample config provides target sound card by name - if (query["device"] ~= nil) then - apihal=_Audio_Hal_Registry[query["device"]] - end - - -- HTML5 test page provides directly HAL api. - if (query["apihal"] ~= nil) then - apihal= query["apihal"] - end - - -- if requested HAL is not found then deny the control - if (apihal == nil) then - AFB:error ("--LUA:Audio_Set_Navigation No Active HAL Found") - return -- refuse control - end - - -- return api or nil when not found - return apihal -end - --- Set Navigation lower sound when play -function _Audio_Set_Navigation(source, args, query) - - -- in strict mode every variables should be declared - local err=0 - local ctlhal={} - local response={} - local apihal={} - - AFB:notice ("LUA:Audio_Set_Use_Case source=%d args=%s query=%s", source, args, query); - - -- Parse Query/Args and if HAL not found then refuse access - apihal= Audio_Parse_Request (source, args, query) - if (apihal == nil) then return 1 end - - - -- if source < 0 then Alsa HookPlugin is closing PCM - if (source < 0) then - -- Ramp Up Multimedia channel synchronously - ctlhal={['label']='Master_Playback_Volume', ['val']=100} - err, response= AFB:servsync (apihal, 'ctlset',ctlhal) - else - -- Ramp Down Multimedia channel synchronously - ctlhal={['label']='Master_Playback_Volume', ['val']=50} - err, response= AFB:servsync (apihal, 'ctlset',ctlhal) - end - - if (err) then - AFB:error("--LUA:Audio_Set_Navigation halapi=%s refuse ctl=%s", apihal, ctlhal) - return 1 -- control refused - end - - - return 0 -- control accepted -end - - --- Select Multimedia mode -function _Audio_Set_Multimedia (source, args, query) - - -- in strict mode every variables should be declared - local err=0 - local ctlhal={} - local response={} - local apihal={} - - AFB:notice ("LUA:Audio_Set_Use_Case source=%d args=%s query=%s", source, args, query); - - -- Parse Query/Args and if HAL not found then refuse access - apihal= Audio_Parse_Request (source, args, query) - if (apihal == nil) then return 1 end - - - -- if Mumtimedia control only increase volume on open - if (source >= 0) then - -- Ramp Down Multimedia channel synchronously - ctlhal={['label']='Master_Playback_Volume', ['val']=100} - err, response= AFB:servsync (apihal, 'ctlset',ctlhal) - end - - if (err) then - AFB:error("--LUA:Audio_Set_Navigation halapi=%s refuse ctl=%s", apihal, ctlhal) - return 1 -- control refused - end - - - return 0 -- control accepted -end - --- Select Emergency Mode -function _Audio_Set_Emergency(source, args, query) - return 1 -- Always refuse in this test -end diff --git a/conf.d/project/lua.d/onload-audio-oncall.lua b/conf.d/project/lua.d/onload-audio-oncall.lua deleted file mode 100644 index 23b538e..0000000 --- a/conf.d/project/lua.d/onload-audio-oncall.lua +++ /dev/null @@ -1,70 +0,0 @@ ---[[ - Copyright (C) 2016 "IoT.bzh" - Author Fulup Ar Foll - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Provide sample LUA routines to be used with AGL control "lua_docall" API ---]] - ---global counter to keep track of calls -_count=0 - --- Display receive arguments and echo them to caller -function _Simple_Echo_Args (request, args) - _count=_count+1 - AFB:notice("LUA OnCall Echo Args count=%d args=%s", count, args) - - print ("--inlua-- args=", Dump_Table(args)) - - local response={ - ["count"]=_count, - ["args"]=args, - } - - -- fulup Embdeded table ToeDone AFB:success (request, response) - AFB:success (request, {["func"]="Simple_Echo_Args", ["ret1"]=5678, ["ret2"]="abcd"}) -end - -local function Test_Async_CB (request, result, context) - response={ - ["result"]=result, - ["context"]=context, - } - - AFB:notice ("Test_Async_CB result=%s context=%s", result, context) - AFB:success (request, response) -end - -function _Test_Call_Async (request, args) - local context={ - ["value1"]="abcd", - ["value2"]=1234 - } - - AFB:notice ("Test_Call_Async args=%s cb=Test_Async_CB", args) - AFB:service("alsacore","ping", "Test_Async_CB", context) -end - -function _Test_Call_Sync (request, args) - - AFB:notice ("Test_Call_Sync args=%s", args) - local err, response= AFB:service_sync ("alsacore","ping", args) - if (err) then - AFB:fail ("AFB:service_call_sync fail"); - else - AFB:success (request, response) - end -end - diff --git a/conf.d/project/lua.d/onload-audio-timer.lua b/conf.d/project/lua.d/onload-audio-timer.lua deleted file mode 100644 index db7a937..0000000 --- a/conf.d/project/lua.d/onload-audio-timer.lua +++ /dev/null @@ -1,69 +0,0 @@ ---[[ - Copyright (C) 2016 "IoT.bzh" - Author Fulup Ar Foll - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Provide Sample Timer Handing to push event from LUA ---]] - --- Create event on Lua script load -local MyEventHandle=AFB:evtmake("MyTestEvent") - --- Call count time every delay/ms -local function Timer_Test_CB (timer, context) - - local evtinfo= AFB:timerget(timer) - print ("timer=", Dump_Table(evtinfo)) - - --send an event an event with count as value - AFB:evtpush (MyEventHandle, {["label"]= evtinfo["label"], ["count"]=evtinfo["count"], ["info"]=context["info"]}) - - -- note when timerCB return!=0 timer is kill - return 0 - -end - --- sendback event depending on count and delay -function _Simple_Timer_Test (request, args) - - local context = { - ["info"]="My 1st private Event", - } - - -- if delay not defined default is 5s - if (args["delay"]==nil) then args["delay"]=5000 end - - -- if count is not defined default is 10 - if (args["count"]==nil) then args["count"]=10 end - - -- we could use directly args but it is a sample - local myTimer = { - ["label"]=args["label"], - ["delay"]=args["delay"], - ["count"]=args["count"], - } - AFB:notice ("Test_Timer myTimer=%s", myTimer) - - -- subscribe to event - AFB:subscribe (request, MyEventHandle) - - -- settimer take a table with delay+count as input (count==0 means infinite) - AFB:timerset (myTimer, "Timer_Test_CB", context) - - -- nothing special to return send back args - AFB:success (request, myTimer) - - return 0 -end diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt deleted file mode 100644 index 3b052c9..0000000 --- a/data/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -########################################################################### -# Copyright 2017 IoT.bzh -# -# author: Fulup Ar Foll -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -########################################################################### - - - -################################################## -# Control Policy Config file -################################################## -PROJECT_TARGET_ADD(Control_config) - - file(GLOB XML_FILES "*.json") - - add_input_files("${XML_FILES}") - - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - LABELS "DATA" - OUTPUT_NAME ${TARGET_NAME} - ) diff --git a/data/default-control-policy.json b/data/default-control-policy.json deleted file mode 100644 index c6f8bd0..0000000 --- a/data/default-control-policy.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "$schema": "ToBeDone", - "metadata": { - "label": "sample-audio-policy", - "info": "Provide Default Audio Policy for Multimedia, Navigation and Emergency", - "version": "1.0" - }, - "onload": { - "info": "controller initialisation config", - "plugin": "sample-audio-policy.so", - "actions": [ - { - "info": "Call policy sharelib install entrypoint", - "callback": "SamplePolicyInstall", - "query": {"arg1" : "first_arg", "nextarg": "second arg value"} - }, { - "info": "Assert AlsaCore Presence", - "api": "alsacore", - "verb": "ping" - } - ] - }, - "controls": - [{ - "label": "multimedia", - "actions": [ - { - "label": "multimedia-policy-cb", - "info": "Call Sharelib Sample Callback", - "callback": "samplePolicyCB", - "query": { - "arg1": "snoopy", - "arg2": "toto" - } - }, { - "label": "multimedia-policy-ucm", - "info": "Subcall AlSA UCM navigation", - "api": "alsacore", - "verb": "ucmset", - "query": { - "verb": "multimedia" - } - } - ] - }, - { - "label":"navigation", - "action" : { - "api": "alsacore", - "verb": "ucmset", - "query": { - "verb": "navigation" - }, - "optional": true, - "timeout": 100 - } - }, { - "label":"emergency", - "action": { - "api": "alsacore", - "verb": "ucmset", - "query": { - "verb": "emergency" - } - } - }] - , - "events": [ - { - "label": "SampleEvent", - "comment": "define action when receiving a given event", - "actions": [ - { - "info": "Event Callback-1", - "callback": "ProcessEventCB", - "query": { - "arg": "action-1" - } - }, { - "info": "Event Callback-2", - "callback": "ProcessEventCB", - "query": { - "arg": "action-2" - } - } - ] - } - ] -} - diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 235c3b0..cf14956 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -49,6 +49,7 @@ ctl-lua.c ctl-misc.c ctl-plugin-sample.c + ctl-policy.c ctl-timer.c @@ -118,11 +119,10 @@ false - - - - - + + + @@ -134,7 +134,7 @@ ${MAKE} -f Makefile install ${MAKE} -f Makefile clean build/CMakeFiles/feature_tests.bin - + @@ -147,11 +147,11 @@ ex="false" tool="0" flavor2="3"> - + - + ../../../opt/include/alsa /usr/include/json-c @@ -162,14 +162,14 @@ - + build/Alsa-afb - + ../../../opt/include/alsa /usr/include/json-c @@ -180,7 +180,7 @@ - + ../../../opt/include/alsa /usr/include/json-c @@ -191,7 +191,7 @@ - + ../../../opt/include/alsa /usr/include/json-c @@ -202,7 +202,7 @@ - + ../../../opt/include/afb Audio-Common @@ -212,7 +212,7 @@ - + ../../../opt/include/afb Audio-Common @@ -222,7 +222,7 @@ - + Audio-Common /usr/include/json-c @@ -231,45 +231,19 @@ - + - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c - /usr/include/lua5.3 - Audio-Common build/Controller-afb - - CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" - CONTROL_CONFIG_POST="control" - CONTROL_CONFIG_PRE="onload" - CONTROL_DOSCRIPT_PRE="doscript" - CONTROL_LUA_EVENT="luaevt" - CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" - CONTROL_MAXPATH_LEN=255 - CONTROL_ONLOAD_DEFAULT="onload-default" - CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" - CONTROL_SUPPORT_LUA - CTL_PLUGIN_MAGIC=2468013579 - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - NATIVE_LINUX - TLV_BYTE_SIZE=256 - control_afb_EXPORTS - - + - ../../../opt/include/afb - Controller-afb /usr/include/json-c /usr/include/lua5.3 Audio-Common @@ -279,10 +253,8 @@ - + - ../../../opt/include/afb - Controller-afb /usr/include/json-c /usr/include/lua5.3 Audio-Common @@ -292,20 +264,16 @@ - + - ../../../opt/include/afb - Controller-afb /usr/include/json-c build/Controller-afb - + - ../../../opt/include/afb - Controller-afb /usr/include/json-c /usr/include/lua5.3 build/Controller-afb @@ -313,10 +281,8 @@ - + - ../../../opt/include/afb - Controller-afb ../../../opt/include build/Controller-afb @@ -326,9 +292,10 @@ ex="false" tool="0" flavor2="3"> - + Audio-Common + ../../../opt/include build/HAL-afb/HAL-interface @@ -337,7 +304,7 @@ ex="false" tool="0" flavor2="3"> - + Audio-Common build/HAL-afb/HAL-interface @@ -345,36 +312,36 @@ - + build/HAL-afb/HAL-interface - + - + - + - + - + Shared-Interface HAL-afb/HAL-interface @@ -383,7 +350,7 @@ - + HAL-afb/HAL-interface build/HAL-afb/Unicens-USB @@ -391,11 +358,11 @@ - + - + @@ -505,6 +472,14 @@ + + + + ../../../opt/include/afb + Controller-afb + + + @@ -2562,5 +2537,655 @@ + + + GNU|GNU + false + false + + + + + + + + + + true + + + + build + ${MAKE} -f Makefile install + ${MAKE} -f Makefile clean + build/CMakeFiles/feature_tests.bin + + + + + build + cmake .. + true + + + + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Alsa-afb + + + CONTROL_MAXPATH_LEN=255 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + alsa_lowlevel_EXPORTS + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include/afb + Alsa-afb + ../../../opt/include/alsa + /usr/include/json-c + Audio-Common + ../../../opt/include + build/Alsa-afb + + + + + + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + ../../../opt/include/afb + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + Audio-Common + /usr/include/json-c + build/Audio-Common + + + + + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/home/fulup/opt/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/home/fulup/opt/controller-plugins/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_PROFILE="onload-default-profile" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/controller-plugins:/usr/lib/afb/controller-plugins/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/home/fulup/opt/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/home/fulup/opt/controller-plugins/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_PROFILE="onload-default-profile" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/controller-plugins:/usr/lib/afb/controller-plugins/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/home/fulup/opt/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/home/fulup/opt/controller-plugins/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_PROFILE="onload-default-profile" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/controller-plugins:/usr/lib/afb/controller-plugins/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + ../../../opt/include/afb + Controller-afb + /usr/include/json-c + build/Controller-afb + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/home/fulup/opt/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/home/fulup/opt/controller-plugins/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_PROFILE="onload-default-profile" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/controller-plugins:/usr/lib/afb/controller-plugins/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/home/fulup/opt/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/home/fulup/opt/controller-plugins/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_PROFILE="onload-default-profile" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/controller-plugins:/usr/lib/afb/controller-plugins/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + TLV_BYTE_SIZE=256 + control_afb_EXPORTS + + + + + + + Audio-Common + build/HAL-afb/HAL-interface + + + + + + + Audio-Common + build/HAL-afb/HAL-interface + + + + + + + build/HAL-afb/HAL-interface + + + + + + + + + + + + + + + + + + + + + + + Shared-Interface + HAL-afb/HAL-interface + build/HAL-afb/Unicens-USB + + + + + + + HAL-afb/HAL-interface + build/HAL-afb/Unicens-USB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alsa-Plugin/Alsa-Policy-Hook + ../../../opt/include/alsa + /usr/include/json-c + ../../../opt/include/afb + ../../../opt/include + build/Alsa-Plugin/Alsa-Policy-Hook + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_DOSCRIPT_PRE="doscript" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CONTROL_SUPPORT_LUA + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + NATIVE_LINUX + PIC + TLV_BYTE_SIZE=256 + policy_hook_cb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + /usr/include/alsa + build/Common + + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + + + + + + + ../../../opt/include/afb + HAL-afb/HAL-interface + + + + + + + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + ../../../opt/include/afb + HAL-afb/HAL-plugin + + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include/afb + HAL-afb/HDA-intel + Audio-Common + HAL-afb/HAL-interface + build/HAL-afb/HDA-intel + + + + + + + HAL-afb/Jabra-Solemate + ../../../opt/include/afb + Audio-Common + HAL-afb/HAL-interface + build/HAL-afb/Jabra-Solemate + + + + + + + ../../../opt/include/afb + HAL-afb/Scarlett-Focusrite + Audio-Common + HAL-afb/HAL-interface + build/HAL-afb/Scarlett-Focusrite + + + + + + + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + ../../../opt/include/afb + HAL-afb/Unicens-USB + + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + ../../../opt/include/afb + HighLevel-afb + Shared-Interface + build/HighLevel-afb + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + + + + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + /usr/include/lua5.3 + Audio-Common + build/Controller-afb + build/HAL-afb/HAL-plugin + + + CONTROL_CONFIG_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/config.d:/usr/local/controller/config.d" + CONTROL_CONFIG_POST="control" + CONTROL_CONFIG_PRE="onload" + CONTROL_LUA_EVENT="luaevt" + CONTROL_LUA_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/conf.d/project/lua.d:/usr/local/controller/ctl-lua.d" + CONTROL_MAXPATH_LEN=255 + CONTROL_ONLOAD_DEFAULT="onload-default" + CONTROL_PLUGIN_PATH="/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build:/home/fulup/opt/audio-bindings/ctlplug:/usr/lib/afb/ctlplug" + CTL_PLUGIN_MAGIC=2468013579 + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + audio_plugin_sample_EXPORTS + control_afb_EXPORTS + + + + diff --git a/nbproject/project.xml b/nbproject/project.xml index db3bdab..b229af2 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -33,6 +33,10 @@ Local_Raw_Controller 0 + + Demo-AudioController + 0 + false -- cgit 1.2.3-korg