diff options
-rw-r--r-- | README.md | 44 | ||||
-rw-r--r-- | afb-source/ctl-binding.h | 8 | ||||
-rw-r--r-- | afb-source/ctl-dispatch.c | 54 | ||||
-rw-r--r-- | afb-source/ctl-policy.c | 96 | ||||
-rw-r--r-- | afb-source/ctl-timer.c | 18 | ||||
-rw-r--r-- | conf.d/project/json.d/README.md | 2 | ||||
-rw-r--r-- | conf.d/project/lua.d/onload-daemon-01-init.lua | 10 | ||||
-rw-r--r-- | conf.d/project/lua.d/onload-daemon-03-controls.lua | 2 | ||||
-rw-r--r-- | conf.d/project/lua.d/onload-daemon-10-event.lua | 4 | ||||
-rw-r--r-- | ctl-plugin/ctl-plugin-sample.c | 20 | ||||
-rw-r--r-- | htdocs/AFB-websock.js | 6 | ||||
-rw-r--r-- | htdocs/AudioBinding.js | 80 | ||||
-rw-r--r-- | htdocs/README.md | 2 | ||||
-rw-r--r-- | htdocs/index.html | 20 |
14 files changed, 183 insertions, 183 deletions
@@ -1,7 +1,7 @@ Controler AAAA(AGL Advance Audio Controler) and more. ------------------------------------------------------------ - * Object: Generic Controler to handle Policy,Small Business Logic, Glue in between components, ... + * 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 @@ -34,20 +34,20 @@ environment variable. Setenv 'CONTROL_ONLOAD_PROFILE'=xxxx to overload 'onload-d ### Config is organised in 4 sections: - * metadata + * 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. + +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. +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 @@ -61,7 +61,7 @@ Defines startup time configuration. Onload may provide multiple initialisation p ### Control section -Defines a list of controls that are accessible through (api="control", verb="request", control="control-label"). +Defines a list of controls that are accessible through (api="control", verb="request", control="control-label"). * label mandatory * info optional @@ -83,10 +83,10 @@ Controler support tree categories of actions. Each action return a status status * 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 + * 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. + 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. @@ -95,14 +95,14 @@ Controler support tree categories of actions. Each action return a status status 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(), ...). +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: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 '{}' @@ -117,14 +117,14 @@ Each Lua AppFw commands should be prefixed by AFB: 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"). + * 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. + 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. @@ -135,7 +135,7 @@ Each Lua AppFw commands should be prefixed by AFB: 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. + * 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. @@ -145,9 +145,9 @@ Note: Except for function call during binding initialisation period. Lua call ar ### 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 +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. @@ -173,7 +173,7 @@ local or as global. Unfortunately "luac" is not smart enough to handle strict mo 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 @@ -226,7 +226,7 @@ Here after a simple configuration sample. } }, { "label": "onload-sample-api", - "info": "Assert AlsaCore Presence", + "info": "Assert AlsaCore Presence", "api": "alsacore", "verb": "ping", "args": "test" @@ -237,14 +237,14 @@ Here after a simple configuration sample. } ] }], - "controls": + "controls": [ { "label": "multimedia", "permissions": "urn:AGL:permission:audio:public:mutimedia", "actions": { "label": "multimedia-control-lua", - "info": "Call Lua Script function Test_Lua_Engin", + "info": "Call Lua Script function Test_Lua_Engin", "lua": "Audio_Set_Multimedia" } }, { @@ -252,7 +252,7 @@ Here after a simple configuration sample. "permissions": "urn:AGL:permission:audio:public:navigation", "actions": { "label": "navigation-control-lua", - "info": "Call Lua Script to set Navigation", + "info": "Call Lua Script to set Navigation", "lua": "Audio_Set_Navigation" } }, { @@ -282,7 +282,7 @@ Here after a simple configuration sample. } }, { "label": "navigation-control-lua", - "info": "Call Lua Script to set Navigation", + "info": "Call Lua Script to set Navigation", "lua": "Audio_Set_Navigation" }] } diff --git a/afb-source/ctl-binding.h b/afb-source/ctl-binding.h index 0d16e56..f159440 100644 --- a/afb-source/ctl-binding.h +++ b/afb-source/ctl-binding.h @@ -70,7 +70,7 @@ typedef enum { CTL_MODE_NONE=0, CTL_MODE_API, CTL_MODE_CB, - CTL_MODE_LUA, + CTL_MODE_LUA, } CtlRequestModeT; @@ -130,14 +130,14 @@ PUBLIC void ctlapi_lua_doscript (afb_req request); // sharelib ctl-plugin* typedef struct { - long magic; - char *label; + 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_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) diff --git a/afb-source/ctl-dispatch.c b/afb-source/ctl-dispatch.c index 95d1315..bbc15ad 100644 --- a/afb-source/ctl-dispatch.c +++ b/afb-source/ctl-dispatch.c @@ -13,7 +13,7 @@ * 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 */ @@ -58,7 +58,7 @@ typedef struct { DispatchHandleT **controls; } DispatchConfigT; -// global config handle +// global config handle STATIC DispatchConfigT *configHandle = NULL; STATIC int DispatchControlToIndex(DispatchHandleT **controls, const char* controlLabel) { @@ -71,7 +71,7 @@ STATIC int DispatchControlToIndex(DispatchHandleT **controls, const char* contro 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; @@ -87,12 +87,12 @@ STATIC int DispatchOneControl(DispatchSourceT source, DispatchHandleT **controls 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); + 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++) { @@ -104,10 +104,10 @@ STATIC int DispatchOneControl(DispatchSourceT source, DispatchHandleT **controls // 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); + 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) { @@ -117,7 +117,7 @@ STATIC int DispatchOneControl(DispatchSourceT source, DispatchHandleT **controls 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"; @@ -180,7 +180,7 @@ PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ) { 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); @@ -192,14 +192,14 @@ PUBLIC void ctlapi_dispatch(afb_req request) { 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: @@ -211,7 +211,7 @@ PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT ca #ifndef CONTROL_SUPPORT_LUA AFB_ERROR("DISPATCH-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake"); return 1; -#else +#else int err=Lua2cWrapper(luaState, funcname, callback, configHandle->plugin->context); return err; #endif @@ -223,13 +223,13 @@ PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT ca 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); @@ -399,7 +399,7 @@ STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_ // 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) { @@ -441,20 +441,20 @@ STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_ struct afb_binding_data_v2 *afbHidenData = dlsym(dPlugin->dlHandle, "afbBindingV2data"); if (afbHidenData) *afbHidenData = afbBindingV2data; - // Push lua2cWrapper @ into plugin + // Push lua2cWrapper @ into plugin Lua2cWrapperT *lua2cInPlug = dlsym(dPlugin->dlHandle, "Lua2cWrap"); -#ifndef CONTROL_SUPPORT_LUA +#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()); @@ -462,14 +462,14 @@ STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_ } 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); @@ -531,8 +531,8 @@ STATIC DispatchConfigT *DispatchLoadConfig(const char* filepath) { 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) { @@ -542,7 +542,7 @@ STATIC DispatchConfigT *DispatchLoadConfig(const char* filepath) { AFB_ERROR("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ)); goto OnErrorExit; } - + // if ctlname is provided change process name now if (ctlname) { err= prctl(PR_SET_NAME, ctlname,NULL,NULL,NULL); @@ -620,7 +620,7 @@ OnErrorExit: 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; @@ -630,7 +630,7 @@ PUBLIC int DispatchInit() { // search for default dispatch config file json_object* responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, controlFile, "json"); - // We load 1st file others are just warnings + // 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); diff --git a/afb-source/ctl-policy.c b/afb-source/ctl-policy.c index e9798b3..9fe220c 100644 --- a/afb-source/ctl-policy.c +++ b/afb-source/ctl-policy.c @@ -19,7 +19,7 @@ #include <stdio.h> #include <string.h> #include <dirent.h> -#include <json-c/json_object.h> +#include <json-c/json_object.h> #include "wrap-json.h" #include "ctl-binding.h" @@ -32,17 +32,17 @@ STATIC json_object* ScanForConfig (char* searchPath) { 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 @@ -54,18 +54,18 @@ STATIC json_object* ScanForConfig (char* searchPath) { } } } - - free (dirList); + + 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; - + } @@ -73,34 +73,34 @@ PUBLIC void ctlapi_authorize (PolicyCtlEnumT control, 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); + } 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"); + 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) { @@ -108,34 +108,34 @@ STATIC PolicyActionT **PolicyLoadActions (json_object *actionsJ) { 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; - } + 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)); + 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 @@ -143,25 +143,25 @@ 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) { @@ -170,9 +170,9 @@ STATIC PolicyCtlConfigT *PolicyLoadConfig (const char* filepath) { } policyConfig->onload = PolicyLoadActions (actionsJ); } - + return policyControl; - + OnErrorExit: return NULL; } @@ -180,42 +180,42 @@ OnErrorExit: // 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)); + 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; + return 1; } - - + + diff --git a/afb-source/ctl-timer.c b/afb-source/ctl-timer.c index a826f9f..50e181b 100644 --- a/afb-source/ctl-timer.c +++ b/afb-source/ctl-timer.c @@ -45,7 +45,7 @@ STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { return 0; } else { - // otherwise validate timer for a new run + // 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); @@ -53,12 +53,12 @@ STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { done= timerHandle->callback(timerHandle->context); if (!done) goto OnErrorExit; - + return 0; OnErrorExit: AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->label); - return -1; + return -1; } PUBLIC void TimerEvtStop(TimerHandleT *timerHandle) { @@ -70,12 +70,12 @@ PUBLIC void TimerEvtStop(TimerHandleT *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 + + // 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); } @@ -87,15 +87,15 @@ PUBLIC afb_event TimerEvtGet(void) { // 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/json.d/README.md b/conf.d/project/json.d/README.md index 153990c..9bd15bf 100644 --- a/conf.d/project/json.d/README.md +++ b/conf.d/project/json.d/README.md @@ -8,7 +8,7 @@ By default controller searches for a config filename with the same 'middlename' You may overload config search path with environement variables * AFB_BINDER_NAME: change patern config search path. 'export AFB_BINDER_NAME=sample' will make controller to search for a configfile name 'onload-sample-xxx.json'. - * CONTROL_CONFIG_PATH: change default reserch path for configuration. You may provide multiple directories separated by ':'. + * CONTROL_CONFIG_PATH: change default reserch path for configuration. You may provide multiple directories separated by ':'. * CONTROL_LUA_PATH: same as CONTROL_CONFIG_PATH but for Lua script files. Example to load a config name 'onload-myconfig-test.json' do diff --git a/conf.d/project/lua.d/onload-daemon-01-init.lua b/conf.d/project/lua.d/onload-daemon-01-init.lua index ebdc678..26ff08a 100644 --- a/conf.d/project/lua.d/onload-daemon-01-init.lua +++ b/conf.d/project/lua.d/onload-daemon-01-init.lua @@ -21,7 +21,7 @@ _Global_Context={} --[[ This function is call during controller init phase as describe in onload-daemon-sample.json It receives two argument 1st one is the source (here on load) second one is the arguments - as expose in config file. + as expose in config file. In this sample we create an event that take the name of args["zzzz"], the resulting handle is save into _Global_Context for further use. @@ -32,17 +32,17 @@ _Global_Context={} function _Sample_Controller_Init(source, control) printf ("[-- Sample_Controller_Init --] source=%d control=%s", source, Dump_Table(control)) - + -- if no argument return now - if (control==nil or control["zzzz"]==nil) then + if (control==nil or control["zzzz"]==nil) then printf ("[-- Sample_Controller_Init --] no event name given") return end -- set a count to make more visible each call _Global_Context["counter"]=0 - + -- just for fun create an event _Global_Context["event"]=AFB:evtmake(control["zzzz"]) -end +end diff --git a/conf.d/project/lua.d/onload-daemon-03-controls.lua b/conf.d/project/lua.d/onload-daemon-03-controls.lua index f65c019..e9c8b51 100644 --- a/conf.d/project/lua.d/onload-daemon-03-controls.lua +++ b/conf.d/project/lua.d/onload-daemon-03-controls.lua @@ -15,7 +15,7 @@ limitations under the License. Following function are called when a client activate a control with - controller api -> APi=control VERB=dispatch + controller api -> APi=control VERB=dispatch arguments are - source (0) when requesting the control (-1) when releasing - control comme from config given with 'args' in onload-middlename-xxxxx.json diff --git a/conf.d/project/lua.d/onload-daemon-10-event.lua b/conf.d/project/lua.d/onload-daemon-10-event.lua index c0b21f9..474ebe0 100644 --- a/conf.d/project/lua.d/onload-daemon-10-event.lua +++ b/conf.d/project/lua.d/onload-daemon-10-event.lua @@ -45,7 +45,7 @@ function _Simple_Timer_Test (request, client) -- if event does not exit create it now. if (_MyContext["event"] == nil) then _MyContext["event"]= AFB:evtmake(client["label"]) - end + end -- if delay not defined default is 5s if (client["delay"]==nil) then client["delay"]=5000 end @@ -67,7 +67,7 @@ function _Simple_Timer_Test (request, client) -- 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 + -- nothing special to return send back AFB:success (request, myTimer) return 0 diff --git a/ctl-plugin/ctl-plugin-sample.c b/ctl-plugin/ctl-plugin-sample.c index 1d66802..300bd1c 100644 --- a/ctl-plugin/ctl-plugin-sample.c +++ b/ctl-plugin/ctl-plugin-sample.c @@ -13,7 +13,7 @@ * 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 */ @@ -28,16 +28,16 @@ typedef struct { int magic; - int count; + int count; } MyPluginCtxT; STATIC const char* jsonToString (json_object *valueJ) { const char *value; if (valueJ) value=json_object_get_string(valueJ); - else + else value="NULL"; - + return value; } @@ -60,7 +60,7 @@ PUBLIC CTLP_CAPI (SamplePolicyInit, source, label, argsJ, queryJ, context) { 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; @@ -68,7 +68,7 @@ PUBLIC CTLP_CAPI (SamplePolicyInit, source, label, argsJ, queryJ, context) { 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; @@ -81,7 +81,7 @@ PUBLIC CTLP_CAPI (sampleControlMultimedia, source, label, argsJ,queryJ,context) 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; @@ -94,7 +94,7 @@ PUBLIC CTLP_CAPI (sampleControlNavigation, source, label, argsJ, queryJ, contex 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; @@ -108,7 +108,7 @@ PUBLIC CTLP_CAPI (SampleControlEvent, source, label, argsJ, queryJ, context) { // 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; @@ -122,7 +122,7 @@ PUBLIC CTLP_LUA2C (Lua2cHelloWorld1, label, argsJ, context) { // 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; diff --git a/htdocs/AFB-websock.js b/htdocs/AFB-websock.js index ff9fa60..99ab3b8 100644 --- a/htdocs/AFB-websock.js +++ b/htdocs/AFB-websock.js @@ -123,14 +123,14 @@ var AFB_websocket; switch (code) { case RETOK: reply(this.pendings, id, ans, 0); - break; + break; case RETERR: reply(this.pendings, id, ans, 1); - break; + break; case EVENT: default: fire(this.awaitens, id, ans); - break; + break; } } diff --git a/htdocs/AudioBinding.js b/htdocs/AudioBinding.js index 4d14600..0f5caf9 100644 --- a/htdocs/AudioBinding.js +++ b/htdocs/AudioBinding.js @@ -37,50 +37,50 @@ if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, " ")); } - + // default soundcard is "PCH" var devid=getParameterByName("devid"); if (!devid) devid="hw:1"; - + var haldev=getParameterByName("haldev"); if (!haldev) haldev="scarlett-usb"; - + var sndname=getParameterByName("sndname"); if (!sndname) sndname="PCH"; - + var mode=getParameterByName("mode"); if (!mode) mode="0"; - + function replyok(obj) { console.log("replyok:" + JSON.stringify(obj)); document.getElementById("output").innerHTML = "OK: "+ syntaxHighlight(obj); } - + function replyerr(obj) { console.log("replyerr:" + JSON.stringify(obj)); document.getElementById("output").innerHTML = "ERROR: "+ syntaxHighlight(obj); } - + function gotevent(obj) { console.log("gotevent:" + JSON.stringify(obj)); document.getElementById("outevt").innerHTML = (evtidx++) +": "+JSON.stringify(obj); } - + function send(message) { var api = document.getElementById("api").value; var verb = document.getElementById("verb").value; document.getElementById("question").innerHTML = "subscribe: "+api+"/"+verb + " (" + JSON.stringify(message) +")"; ws.call(api+"/"+verb, {data:message}).then(replyok, replyerr); } - - // On button click from HTML page + + // On button click from HTML page function callbinder(api, verb, query) { console.log ("subscribe api="+api+" verb="+verb+" query=" +query); - var question = urlws +"/" +api +"/" +verb + "?query=" + JSON.stringify(query); + var question = urlws +"/" +api +"/" +verb + "?query=" + JSON.stringify(query); document.getElementById("question").innerHTML = syntaxHighlight(question); ws.call(api+"/"+verb, query).then(replyok, replyerr); } @@ -89,26 +89,26 @@ // Retreive Select value and Text from the binder // Note: selection of value/text for a given context is huggly!!! function querySelectList (elemid, api, verb, query) { - + console.log("querySelectList elemid=%s api=%s verb=%s query=%s", elemid, api, verb, query); - + var selectobj = document.getElementById(elemid); if (!selectobj) { return; } - + // onlick update selected HAL api selectobj.onclick=function(){ - sndcard= this.value; - console.log ("Default Selection=" + sndcard); + sndcard= this.value; + console.log ("Default Selection=" + sndcard); }; function gotit (result) { - + // display response as for normal onclick action replyok(result); var response=result.response; - + // fulfill select with avaliable active HAL for (idx=0; idx<response.length; idx++) { var opt = document.createElement('option'); @@ -120,39 +120,39 @@ // HAL selection mode if (response[idx].shortname) opt.text = response[idx].shortname; if (response[idx].api) opt.value = response[idx].api; - + selectobj.appendChild(opt); } - + sndcard= selectobj.value; } - - var question = urlws +"/"+api +"/" +verb + "?query=" + JSON.stringify(query); + + var question = urlws +"/"+api +"/" +verb + "?query=" + JSON.stringify(query); document.getElementById("question").innerHTML = syntaxHighlight(question); // request lowlevel ALSA to get API list ws.call(api+"/"+verb, query).then(gotit, replyerr); } - + function refresh_list (self, api, verb, query) { console.log("refresh_list id=%s api=%s verb=%s query=%s", self.id, api, verb, query); - - if (self.value > 0) return; - + + if (self.value > 0) return; + // onlick update selected HAL api self.onclick=function(){ - numid = parseInt(self.value); - console.log ("Default numid=%d", numid); + numid = parseInt(self.value); + console.log ("Default numid=%d", numid); }; function gotit (result) { - + // display response as for normal onclick action replyok(result); var response=result.response; - + // fulfill select with avaliable active HAL for (idx=0; idx<response.length; idx++) { var opt = document.createElement('option'); @@ -160,27 +160,27 @@ // Alsa LowLevel selection mode opt.text = response[idx].name + ' id=' + response[idx].id; opt.value = response[idx].id; - + self.appendChild(opt); - } + } self.selectedIndex=2; - numid = parseInt (self.value); + numid = parseInt (self.value); } - - var question = urlws +"/"+api +"/" +verb + "?query=" + JSON.stringify(query); + + var question = urlws +"/"+api +"/" +verb + "?query=" + JSON.stringify(query); document.getElementById("question").innerHTML = syntaxHighlight(question); // request lowlevel ALSA to get API list ws.call(api+"/"+verb, query).then(gotit, replyerr); } - - + + function init(elemid, api, verb, query) { - + function onopen() { // check for active HALs querySelectList (elemid, api, verb, query); - + document.getElementById("main").style.visibility = "visible"; document.getElementById("connected").innerHTML = "Binder WS Active"; document.getElementById("connected").style.background = "lightgreen"; @@ -192,6 +192,6 @@ document.getElementById("connected").innerHTML = "Connected Closed"; document.getElementById("connected").style.background = "red"; - } + } ws = new afb.ws(onopen, onabort); } diff --git a/htdocs/README.md b/htdocs/README.md index 0ad2260..7aafea0 100644 --- a/htdocs/README.md +++ b/htdocs/README.md @@ -1,7 +1,7 @@ ------------------------------------------------------------------------ Basic HTML & WS test ------------------------------------------------------------------------ - + # Load bindings directly from development tree for debug AFB_BINDER_NAME='sample' afb-daemon --verbose --verbose --token="" --ldpaths=build --port=1234 --roothttp=htdocs diff --git a/htdocs/index.html b/htdocs/index.html index 19d5315..52baba3 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -5,31 +5,31 @@ <script type="text/javascript" src="AFB-websock.js"></script> <script type="text/javascript" src="AudioBinding.js"></script> </head> - + <body onload="init('hal_registry','alsacore', 'hallist')"> - + <h1>Simple Control Test</h1> <button id="connected" onclick="init('hal_registry','alsacore', 'hallist')">Binder WS Fail</button> <br><br> - + <ol> - + <li><button onclick="callbinder('control','dispatch' ,{'target':'Button-Happy',args:{'var1':1234, 'var2':4567}});">Button Happy (Granted)</button></li> <li><button onclick="callbinder('control','dispatch' ,{'target':'Button-UnHappy',args:{'var1':1234, 'var2':4567}});">Button UnHappy (Refused)</button></li> - <br> + <br> <li><button onclick="callbinder('control','request' ,{'target':'_Simple_Timer_Test',args:{'label':'myTimer', 'delay':3000, 'count':10}});">Start Events Timer</button></li> - <br> + <br> <li><button onclick="callbinder('control','request' ,{'target':'_Simple_Echo_Args', 'args':{speed:20}});">Simple Echo args</button></li> - <br> + <br> <li><button onclick="callbinder('control','debuglua' ,{'target':'helloworld', args:{'arg1':'abcd', 'next':7890, 'last':[1,2,3,4]}});">Lua Debug Script</button></li> - + </ol> - + <div id="main" style="visibility:hidden"> <ol> <li>Question <pre id="question"></pre> <li>Response <pre id="output"></pre> <li>Events: <pre id="outevt"></pre> </ol> - </div> + </div> |