From 78202d5bd8a8d09a55bb71b9df6d3f54b18184b8 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Wed, 20 Sep 2017 16:54:14 +0200 Subject: Make LUA works - Added LUA library at link - Make app-template crash build if a checked file fails - Fix old defined variable CONTROL_LUA_PATH to a default one in the binding data directory - Add an example with unit conversion made in LUA Change-Id: I1b4712bde32a38044ad6b14ebd38b6782fd01fe9 Signed-off-by: Romain Forlot --- conf.d/app-templates | 2 +- conf.d/autobuild/agl/autobuild | 8 +- conf.d/autobuild/linux/autobuild | 8 +- conf.d/cmake/00-debian-osconfig.cmake | 1 + conf.d/cmake/00-default-osconfig.cmake | 1 + conf.d/cmake/00-suse-config.cmake | 3 +- conf.d/cmake/config.cmake | 2 +- conf.d/cmake/low-can.c | 157 +++++++++++++++++++++ conf.d/project/etc/init-daemon.json | 4 +- conf.d/project/etc/sig-demoboard.json | 7 +- conf.d/project/etc/sources.json | 10 +- conf.d/project/lua.d/00-viwi-low-can.lua | 27 ---- conf.d/project/lua.d/doscript-helloworld.lua | 36 ----- conf.d/project/lua.d/init-daemon-00-utils.lua | 86 +++++++++++ conf.d/project/lua.d/init-daemon-01-init.lua | 47 ++++++ conf.d/project/lua.d/init-daemon-03-controls.lua | 48 +++++++ conf.d/project/lua.d/init-daemon-04-oncall.lua | 117 +++++++++++++++ conf.d/project/lua.d/init-daemon-10-event.lua | 74 ++++++++++ conf.d/project/lua.d/onload-daemon-00-utils.lua | 86 ----------- conf.d/project/lua.d/onload-daemon-01-init.lua | 48 ------- conf.d/project/lua.d/onload-daemon-03-controls.lua | 48 ------- conf.d/project/lua.d/onload-daemon-04-oncall.lua | 70 --------- conf.d/project/lua.d/onload-daemon-10-event.lua | 74 ---------- controller/CMakeLists.txt | 10 +- controller/ctl-config.c | 5 +- controller/ctl-config.h | 16 ++- controller/ctl-lua.c | 15 +- controller/ctl-lua.h | 16 ++- controller/ctl-plugin.c | 8 -- controller/ctl-plugin.h | 8 ++ plugins/CMakeLists.txt | 27 +++- plugins/low-can.c | 157 --------------------- plugins/low-can.cpp | 3 +- plugins/lua2c-interface.c | 56 ++++++++ .../signal-composer-binding.cpp | 12 +- signal-composer-binding/signal-composer.cpp | 21 ++- signal-composer-binding/signal-composer.hpp | 1 + signal-composer-binding/signal.cpp | 6 +- signal-composer-binding/signal.hpp | 7 +- signal-composer-binding/source.cpp | 16 ++- signal-composer-binding/source.hpp | 1 + 41 files changed, 725 insertions(+), 624 deletions(-) create mode 100644 conf.d/cmake/00-debian-osconfig.cmake create mode 100644 conf.d/cmake/00-default-osconfig.cmake create mode 100644 conf.d/cmake/low-can.c delete mode 100644 conf.d/project/lua.d/00-viwi-low-can.lua delete mode 100644 conf.d/project/lua.d/doscript-helloworld.lua create mode 100644 conf.d/project/lua.d/init-daemon-00-utils.lua create mode 100644 conf.d/project/lua.d/init-daemon-01-init.lua create mode 100644 conf.d/project/lua.d/init-daemon-03-controls.lua create mode 100644 conf.d/project/lua.d/init-daemon-04-oncall.lua create mode 100644 conf.d/project/lua.d/init-daemon-10-event.lua delete mode 100644 conf.d/project/lua.d/onload-daemon-00-utils.lua delete mode 100644 conf.d/project/lua.d/onload-daemon-01-init.lua delete mode 100644 conf.d/project/lua.d/onload-daemon-03-controls.lua delete mode 100644 conf.d/project/lua.d/onload-daemon-04-oncall.lua delete mode 100644 conf.d/project/lua.d/onload-daemon-10-event.lua delete mode 100644 plugins/low-can.c create mode 100644 plugins/lua2c-interface.c diff --git a/conf.d/app-templates b/conf.d/app-templates index 908a037..3465ddb 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 908a0372d53c74a037da3debe1e276a214343c41 +Subproject commit 3465ddbdec8d77e2a59315e50f954ea2d35aa1cb diff --git a/conf.d/autobuild/agl/autobuild b/conf.d/autobuild/agl/autobuild index 4811441..3a1ba5f 100755 --- a/conf.d/autobuild/agl/autobuild +++ b/conf.d/autobuild/agl/autobuild @@ -29,8 +29,9 @@ help: @echo "- clean" @echo "- distclean" @echo "- configure" - @echo "- build" - @echo "- package" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" @echo "" @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" @echo "Don't use your build dir as DEST as wgt file is generated at this location" @@ -58,6 +59,9 @@ package: build @cmake --build ${BUILD_DIR} --target widget @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} +install: build + @cmake --build ${BUILD_DIR} --target install + ${BUILD_DIR}/Makefile: @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/autobuild/linux/autobuild b/conf.d/autobuild/linux/autobuild index 4811441..3a1ba5f 100755 --- a/conf.d/autobuild/linux/autobuild +++ b/conf.d/autobuild/linux/autobuild @@ -29,8 +29,9 @@ help: @echo "- clean" @echo "- distclean" @echo "- configure" - @echo "- build" - @echo "- package" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" @echo "" @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" @echo "Don't use your build dir as DEST as wgt file is generated at this location" @@ -58,6 +59,9 @@ package: build @cmake --build ${BUILD_DIR} --target widget @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} +install: build + @cmake --build ${BUILD_DIR} --target install + ${BUILD_DIR}/Makefile: @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/cmake/00-debian-osconfig.cmake b/conf.d/cmake/00-debian-osconfig.cmake new file mode 100644 index 0000000..2ce0ad3 --- /dev/null +++ b/conf.d/cmake/00-debian-osconfig.cmake @@ -0,0 +1 @@ +list(APPEND PKG_REQUIRED_LIST lua-5.3>=5.3) diff --git a/conf.d/cmake/00-default-osconfig.cmake b/conf.d/cmake/00-default-osconfig.cmake new file mode 100644 index 0000000..a2b9325 --- /dev/null +++ b/conf.d/cmake/00-default-osconfig.cmake @@ -0,0 +1 @@ +list(APPEND PKG_REQUIRED_LIST lua>=5.3) diff --git a/conf.d/cmake/00-suse-config.cmake b/conf.d/cmake/00-suse-config.cmake index 0c40b68..8c8303b 100644 --- a/conf.d/cmake/00-suse-config.cmake +++ b/conf.d/cmake/00-suse-config.cmake @@ -1 +1,2 @@ -add_definitions(-DSUSE_LUA_INCDIR) \ No newline at end of file +add_definitions(-DSUSE_LUA_INCDIR) +list(APPEND PKG_REQUIRED_LIST lua>=5.3) diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index d2f31ae..4f2cf71 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -125,7 +125,7 @@ set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt) # -O2 # CACHE STRING "Compilation flags for RELEASE build type.") -add_definitions("-DCONTROL_CONFIG_PRE=\"init\"") +add_definitions("-DCONTROL_SUPPORT_LUA=1") add_definitions("-DCTL_PLUGIN_MAGIC=3286576532") # (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable] diff --git a/conf.d/cmake/low-can.c b/conf.d/cmake/low-can.c new file mode 100644 index 0000000..86f0f5c --- /dev/null +++ b/conf.d/cmake/low-can.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Romain Forlot + * + * 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 // needed for vasprintf + +#define AFB_BINDING_VERSION 2 +#include +#include +#include +#include +#include + +#include "ctl-plugin.h" +#include "wrap-json.h" + +CTLP_REGISTER("low-can"); + +typedef struct { + bool door; + bool window; +} doorT; + +typedef struct { + doorT* front_left; + doorT* front_right; + doorT* rear_left; + doorT* rear_right; +} allDoorsCtxT; + +// Call at initialisation time +CTLP_ONLOAD(plugin, api) { + allDoorsCtxT *allDoorCtx = (allDoorsCtxT*)calloc (1, sizeof(allDoorsCtxT)); + memset(allDoorCtx, 0, sizeof(allDoorsCtxT)); + + AFB_NOTICE ("Low-can plugin: label='%s' version='%s' info='%s'", plugin->label, plugin->version, plugin->info); + return (void*)allDoorCtx; +} + +CTLP_CAPI (subscribeToLow, source, argsJ, eventJ, context) { + json_object* signalArrayJ = NULL, *subscribeArgsJ = NULL, *subscribeFilterJ = NULL, *responseJ = NULL; + const char* unit = NULL; + double frequency = 0; + int err = 0; + + err = wrap_json_unpack(eventJ, "{so,s?s,s?F !}", + "signal", &signalArrayJ, + "unit", &unit, + "frequency", &frequency); + if(err) + { + AFB_ERROR("Problem to unpack JSON object eventJ: %s", + json_object_to_json_string(eventJ)); + return err; + } + + if(frequency > 0) + { + wrap_json_pack(&subscribeFilterJ, "{sf}", "frequency", frequency); + } + + for (int idx = 0; idx < json_object_array_length(signalArrayJ); idx++) + { + json_object* aSignalJ = json_object_array_get_idx(signalArrayJ, idx); + err = wrap_json_pack(&subscribeArgsJ, "{ss, so*}", + "event", json_object_get_string(aSignalJ), + "filter", subscribeFilterJ); + if(err) + { + AFB_ERROR("Error building subscription query object"); + return err; + } + AFB_DEBUG("Calling subscribe with %s", json_object_to_json_string_ext(subscribeArgsJ, JSON_C_TO_STRING_PRETTY)); + err = afb_service_call_sync("low-can", "subscribe", subscribeArgsJ, &responseJ); + if(err) + { + AFB_ERROR("Can't find api 'low-can'"); + return err; + } + } + + return err; +} + +CTLP_CAPI (isOpen, source, argsJ, eventJ, context) { + + const char* eventName; + json_object *eventStatus = NULL; + long long int *timestamp = NULL; + allDoorsCtxT *ctx=(allDoorsCtxT*)context; + + AFB_DEBUG("Here is the situation: source:%s, args:%s, event:%s,\n fld: %s, flw: %s, frd: %s, frw: %s, rld: %s, rlw: %s, rrd: %s, rrw: %s", + source->label, + json_object_to_json_string(argsJ), + json_object_to_json_string(eventJ), + ctx->front_left->door ? "true":"false", + ctx->front_left->window ? "true":"false", + ctx->front_right->door ? "true":"false", + ctx->front_right->window ? "true":"false", + ctx->rear_left->door ? "true":"false", + ctx->rear_left->window ? "true":"false", + ctx->rear_right->door ? "true":"false", + ctx->rear_right->window ? "true":"false" + ); + + int err = wrap_json_unpack(eventJ, "{ss,sb,s?F}", + "event", &eventName, + "value", &eventStatus, + "timestamp", ×tamp); + if(err) + { + AFB_ERROR("Error parsing event %s", json_object_to_json_string(eventJ)); + return -1; + } + + if(strcasestr(eventName, "front_left")) + { + if(strcasestr(eventName, "door")) {ctx->front_left->door = eventStatus;} + else if(strcasestr(eventName, "window")) {ctx->front_left->window = eventStatus;} + else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} + } + else if(strcasestr(eventName, "front_right")) + { + if(strcasestr(eventName, "door")) {ctx->front_right->door = eventStatus;} + else if(strcasestr(eventName, "window")) {ctx->front_right->window = eventStatus;} + else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} + } + else if(strcasestr(eventName, "rear_left")) + { + if(strcasestr(eventName, "door")) {ctx->rear_left->door = eventStatus;} + else if(strcasestr(eventName, "window")) {ctx->rear_left->window = eventStatus;} + else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} + } + else if(strcasestr(eventName, "rear_right")) + { + if(strcasestr(eventName, "door")) {ctx->rear_right->door = eventStatus;} + else if(strcasestr(eventName, "window")) {ctx->rear_right->window = eventStatus;} + else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} + } + else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} + + return 0; +} diff --git a/conf.d/project/etc/init-daemon.json b/conf.d/project/etc/init-daemon.json index a1f75f5..045f3fe 100644 --- a/conf.d/project/etc/init-daemon.json +++ b/conf.d/project/etc/init-daemon.json @@ -3,10 +3,10 @@ "metadata": { "label": "Signal Composer", "version": "1.0", - "api": "signal-composer", + "api": "test", "info": "Signal composer Configuration", "require": ["low-can"], - "files": ["sources", "sig-doors"] + "files": ["sources", "sig-doors", "sig-demoboard"] }, "plugins": [ { diff --git a/conf.d/project/etc/sig-demoboard.json b/conf.d/project/etc/sig-demoboard.json index 3d03f3e..5eb662c 100644 --- a/conf.d/project/etc/sig-demoboard.json +++ b/conf.d/project/etc/sig-demoboard.json @@ -6,9 +6,12 @@ "class": "temporal", "unit": "km/h", "frequency": 1, + "getSignalsArgs": { + "frequency": 5, + "min": 10 + }, "onReceived": { - "label": "Unit converter", - "lua": "_Unit_Converter", + "function": "lua://_Unit_Converter", "args": { "from": "km/h", "to": "mi/h" diff --git a/conf.d/project/etc/sources.json b/conf.d/project/etc/sources.json index be99a41..dcb55a3 100644 --- a/conf.d/project/etc/sources.json +++ b/conf.d/project/etc/sources.json @@ -3,12 +3,6 @@ { "api": "low-can", "info": "Low level binding to handle CAN bus communications", - "init": { - "function": "api://low-can/subscribe", - "args": { - "event": "message*" - } - }, "getSignals": { "function": "plugin://low-can-callbacks/subscribeToLow", "args": { @@ -19,9 +13,9 @@ "api": "gps", "info": "Low level binding which retrieve Satellite positionning values", "init": { - "function": "api://gps/location", + "function": "api://gps/subscribe", "args": { - "arg1": "first argument" + "value": "location" } }, "getSignals": { diff --git a/conf.d/project/lua.d/00-viwi-low-can.lua b/conf.d/project/lua.d/00-viwi-low-can.lua deleted file mode 100644 index b13863a..0000000 --- a/conf.d/project/lua.d/00-viwi-low-can.lua +++ /dev/null @@ -1,27 +0,0 @@ ---[[ - Copyright (C) 2017 "IoT.bzh" - Author Romain Forlot - - 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. ---]] - -function _SubscribeLowCan (request, args) - - AFB:notice ("_We gonna subscribe to %s", args) - local err, result= AFB:servsync ("low-can","subscribe", args) - if (err) then - AFB:fail ("AFB:service_call_sync fail"); - else - AFB:success (request, result["response"]) - end -end diff --git a/conf.d/project/lua.d/doscript-helloworld.lua b/conf.d/project/lua.d/doscript-helloworld.lua deleted file mode 100644 index e722db7..0000000 --- a/conf.d/project/lua.d/doscript-helloworld.lua +++ /dev/null @@ -1,36 +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. - - - Simple API script to be use with AGL control LuaDoCall API - - After the script is loaded by lua_docall - - Controller start function=xxxx where xxxx is taken from script filename doscript-xxxx-anything - ---]] - -function _helloworld (request, query) - - AFB:notice ("LUA HelloWorld: Simple test query=%s", query); - - if (query == nil) then - AFB:notice ("LUA HelloWorld:FX query should not be empty"); - AFB:fail (request, "LUA HelloWorld: query should not be empty"); - else - AFB:notice ("LUA HelloWorld:OK query=%s", query); - AFB:success (request, {arg0="Demat", arg1="Bonjours", arg2="Gootentag", arg3="Morning"}); - end - -end diff --git a/conf.d/project/lua.d/init-daemon-00-utils.lua b/conf.d/project/lua.d/init-daemon-00-utils.lua new file mode 100644 index 0000000..29d2c70 --- /dev/null +++ b/conf.d/project/lua.d/init-daemon-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/init-daemon-01-init.lua b/conf.d/project/lua.d/init-daemon-01-init.lua new file mode 100644 index 0000000..0b8a923 --- /dev/null +++ b/conf.d/project/lua.d/init-daemon-01-init.lua @@ -0,0 +1,47 @@ +--[[ + 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. +--]] + +-- Global variable SHOULD start with _ +_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. + + 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. + + Note: init functions are not call from a client and thus do not receive query +--]] + +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 + 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 diff --git a/conf.d/project/lua.d/init-daemon-03-controls.lua b/conf.d/project/lua.d/init-daemon-03-controls.lua new file mode 100644 index 0000000..cc13e0f --- /dev/null +++ b/conf.d/project/lua.d/init-daemon-03-controls.lua @@ -0,0 +1,48 @@ +--[[ + 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. + + Following function are called when a client activate a control with + 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 + - client is the argument part of the query as providing by client requesting the control. + +--]] + + + +-- Simple Happy(granted) Control +function _Button_Happy(source, control, client) + + -- print argument to make sure we understant what we get + printf ("[-- _Button_Happy --] source=%d control=%s client=%s", source, Dump_Table(control), Dump_Table(client)) + + AFB:notice ("[-- _Button_Happy --] To Be Done") + + return 0 -- control granted +end + + +-- Simple UnHappy(debu) Control +function _Button_UnHappy(source, control, client) + + -- print argument to make sure we understant what we get + printf ("[-- _Button_UnHappy --] source=%d control=%s client=%s", source, Dump_Table(client), Dump_Table(control)) + + AFB:error ("[-- _Button_UnHappy --] To Be Done") + return 1 -- control is refused +end diff --git a/conf.d/project/lua.d/init-daemon-04-oncall.lua b/conf.d/project/lua.d/init-daemon-04-oncall.lua new file mode 100644 index 0000000..ae16aa7 --- /dev/null +++ b/conf.d/project/lua.d/init-daemon-04-oncall.lua @@ -0,0 +1,117 @@ +--[[ + 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 + + +_interval={ + {"km/h",1}, --the "1" should never really get used but + {"mi/h",0.62137119223733}, + {"m/s",0.27777777777778}, +} + +_positions={} +for i=1,3 do + _positions[_interval[i][1]]=i +end + +--function _Unit_Converter(value, sourceunits, targetunits) +function _Unit_Converter(source, args, event) + local value = event["value"] + local sourceunits = args["from"] + local targetunits = args["to"] + local sourcei, targeti = _positions[sourceunits], _positions[targetunits] + assert(sourcei and targeti) + + AFB:notice("LUA OnCall Echo Args source=%s args=%s event=%s", source, args, event) + + if sourceitargeti then + + local base=1 + for i=targeti+1,sourcei do + base=base*interval[i][2] + end + + print("Value in ", targetunits, "is", value*base) + + else + print("No conversion") + end +end + +-- Display receive arguments and echo them to caller +function _Simple_Echo_Args (source, args, event) + _count=_count+1 + AFB:notice("LUA OnCall Echo Args count=%d args=%s event=%s", count, args, event) + + print ("--inlua-- source=", Dump_Table(source)) + print ("--inlua-- args=", Dump_Table(args)) + print ("--inlua-- event=", Dump_Table(event)) + + local response={ + ["count"]=_count, + ["args"]=args, + } + + -- fulup Embdeded table ToeDone AFB:success (request, response) + -- AFB:success (request, response) +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("monitor","ping", "Test_Async_CB", context) +end + +function _Simple_Monitor_Call (request, args) + + AFB:notice ("_Simple_Server_Call args=%s", args) + local err, result= AFB:servsync ("monitor","get", args) + if (err) then + AFB:fail ("AFB:service_call_sync fail"); + else + AFB:success (request, result["response"]) + end +end + diff --git a/conf.d/project/lua.d/init-daemon-10-event.lua b/conf.d/project/lua.d/init-daemon-10-event.lua new file mode 100644 index 0000000..474ebe0 --- /dev/null +++ b/conf.d/project/lua.d/init-daemon-10-event.lua @@ -0,0 +1,74 @@ +--[[ + 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 +_MyContext={} + +-- WARNING: call back are global and should start with '_' +function _Timer_Test_CB (timer, context) + + local evtinfo= AFB:timerget(timer) + printf ("[-- _Timer_Test_C --] evtInfo=%s", Dump_Table(evtinfo)) + + --send an event an event with count as value + AFB:evtpush (_MyContext["event"], {["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, client) + + local context = { + ["info"]="My 1st private Event", + } + + -- if event does not exit create it now. + if (_MyContext["event"] == nil) then + _MyContext["event"]= AFB:evtmake(client["label"]) + end + + -- if delay not defined default is 5s + if (client["delay"]==nil) then client["delay"]=5000 end + + -- if count is not defined default is 10 + if (client["count"]==nil) then client["count"]=10 end + + -- we could use directly client but it is a sample + local myTimer = { + ["label"]=client["label"], + ["delay"]=client["delay"], + ["count"]=client["count"], + } + AFB:notice ("Test_Timer myTimer=%s", myTimer) + + -- subscribe to event + AFB:subscribe (request, _MyContext["event"]) + + -- 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 + AFB:success (request, myTimer) + + return 0 +end diff --git a/conf.d/project/lua.d/onload-daemon-00-utils.lua b/conf.d/project/lua.d/onload-daemon-00-utils.lua deleted file mode 100644 index 29d2c70..0000000 --- a/conf.d/project/lua.d/onload-daemon-00-utils.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-daemon-01-init.lua b/conf.d/project/lua.d/onload-daemon-01-init.lua deleted file mode 100644 index 26ff08a..0000000 --- a/conf.d/project/lua.d/onload-daemon-01-init.lua +++ /dev/null @@ -1,48 +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. ---]] - --- Global variable SHOULD start with _ -_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. - - 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. - - Note: init functions are not call from a client and thus do not receive query - ---]] -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 - 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 diff --git a/conf.d/project/lua.d/onload-daemon-03-controls.lua b/conf.d/project/lua.d/onload-daemon-03-controls.lua deleted file mode 100644 index cc13e0f..0000000 --- a/conf.d/project/lua.d/onload-daemon-03-controls.lua +++ /dev/null @@ -1,48 +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. - - Following function are called when a client activate a control with - 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 - - client is the argument part of the query as providing by client requesting the control. - ---]] - - - --- Simple Happy(granted) Control -function _Button_Happy(source, control, client) - - -- print argument to make sure we understant what we get - printf ("[-- _Button_Happy --] source=%d control=%s client=%s", source, Dump_Table(control), Dump_Table(client)) - - AFB:notice ("[-- _Button_Happy --] To Be Done") - - return 0 -- control granted -end - - --- Simple UnHappy(debu) Control -function _Button_UnHappy(source, control, client) - - -- print argument to make sure we understant what we get - printf ("[-- _Button_UnHappy --] source=%d control=%s client=%s", source, Dump_Table(client), Dump_Table(control)) - - AFB:error ("[-- _Button_UnHappy --] To Be Done") - return 1 -- control is refused -end diff --git a/conf.d/project/lua.d/onload-daemon-04-oncall.lua b/conf.d/project/lua.d/onload-daemon-04-oncall.lua deleted file mode 100644 index 7c0e9bc..0000000 --- a/conf.d/project/lua.d/onload-daemon-04-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 _LUA_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("monitor","ping", "Test_Async_CB", context) -end - -function _Simple_Monitor_Call (request, args) - - AFB:notice ("_Simple_Server_Call args=%s", args) - local err, result= AFB:servsync ("monitor","get", args) - if (err) then - AFB:fail ("AFB:service_call_sync fail"); - else - AFB:success (request, result["response"]) - end -end - diff --git a/conf.d/project/lua.d/onload-daemon-10-event.lua b/conf.d/project/lua.d/onload-daemon-10-event.lua deleted file mode 100644 index 474ebe0..0000000 --- a/conf.d/project/lua.d/onload-daemon-10-event.lua +++ /dev/null @@ -1,74 +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 -_MyContext={} - --- WARNING: call back are global and should start with '_' -function _Timer_Test_CB (timer, context) - - local evtinfo= AFB:timerget(timer) - printf ("[-- _Timer_Test_C --] evtInfo=%s", Dump_Table(evtinfo)) - - --send an event an event with count as value - AFB:evtpush (_MyContext["event"], {["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, client) - - local context = { - ["info"]="My 1st private Event", - } - - -- if event does not exit create it now. - if (_MyContext["event"] == nil) then - _MyContext["event"]= AFB:evtmake(client["label"]) - end - - -- if delay not defined default is 5s - if (client["delay"]==nil) then client["delay"]=5000 end - - -- if count is not defined default is 10 - if (client["count"]==nil) then client["count"]=10 end - - -- we could use directly client but it is a sample - local myTimer = { - ["label"]=client["label"], - ["delay"]=client["delay"], - ["count"]=client["count"], - } - AFB:notice ("Test_Timer myTimer=%s", myTimer) - - -- subscribe to event - AFB:subscribe (request, _MyContext["event"]) - - -- 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 - AFB:success (request, myTimer) - - return 0 -end diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt index b3d0c32..6b4662e 100644 --- a/controller/CMakeLists.txt +++ b/controller/CMakeLists.txt @@ -15,16 +15,15 @@ # See the License for the specific language governing permissions and # limitations under the License. ########################################################################### - # Include LUA only when requested -if(CONTROL_SUPPORT_LUA) +get_property(COMPDEF DIRECTORY PROPERTY COMPILE_DEFINITIONS) +if("CONTROL_SUPPORT_LUA=1" IN_LIST COMPDEF) message(STATUS "Notice: LUA Controler Support Selected") set(CTL_LUA_SOURCE ctl-lua.c ctl-timer.c) ADD_COMPILE_OPTIONS(-DCONTROL_SUPPORT_LUA) -else(CONTROL_SUPPORT_LUA) +else() message(STATUS "Warning: LUA Without Support ") -endif(CONTROL_SUPPORT_LUA) - +endif() # Add target to project dependency list PROJECT_TARGET_ADD(afb-controller) @@ -41,4 +40,3 @@ PROJECT_TARGET_ADD(afb-controller) TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) - diff --git a/controller/ctl-config.c b/controller/ctl-config.c index 888b420..580c68c 100644 --- a/controller/ctl-config.c +++ b/controller/ctl-config.c @@ -155,6 +155,9 @@ int CtlConfigExec(CtlConfigT *ctlConfig) { errcount += ctlConfig->sections[idx].loadCB(&ctlConfig->sections[idx], NULL); } return errcount; + + OnErrorExit: + return 1; } CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections) { @@ -163,7 +166,7 @@ CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections) { int err; #ifdef CONTROL_SUPPORT_LUA - err= LuaConfigLoad(); + err = LuaConfigLoad(); if (err) goto OnErrorExit; #endif diff --git a/controller/ctl-config.h b/controller/ctl-config.h index 590a265..25a066c 100644 --- a/controller/ctl-config.h +++ b/controller/ctl-config.h @@ -21,14 +21,14 @@ #ifndef _CTL_CONFIG_INCLUDE_ #define _CTL_CONFIG_INCLUDE_ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - #ifdef __cplusplus extern "C" { #endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #define AFB_BINDING_VERSION 2 #include #include @@ -42,7 +42,7 @@ extern "C" { #endif #ifndef CONTROL_CONFIG_PRE - #define CONTROL_CONFIG_PRE "onload" + #define CONTROL_CONFIG_PRE "init" #endif #ifndef CTL_PLUGIN_EXT @@ -90,7 +90,11 @@ typedef struct { } CtlConfigT; #ifdef CONTROL_SUPPORT_LUA - #include "ctl-lua.h" + #include "ctl-lua.h" +#else + typedef struct lua_State lua_State; + typedef void *Lua2cFunctionT; + typedef void* Lua2cWrapperT; #endif // ctl-action.c diff --git a/controller/ctl-lua.c b/controller/ctl-lua.c index 5d959f0..7e51d2a 100644 --- a/controller/ctl-lua.c +++ b/controller/ctl-lua.c @@ -736,12 +736,13 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { goto OnErrorExit; } - // search for filename=script in CONTROL_LUA_PATH - if (!luaScriptPathJ) { + // search for filename=script in binding data dir + if (!luaScriptPathJ) { + const char* dirList = strncat(GetBindingDirPath(), "/data", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1); strncpy(luaScriptPath,CONTROL_DOSCRIPT_PRE, sizeof(luaScriptPath)); strncat(luaScriptPath,"-", sizeof(luaScriptPath)); strncat(luaScriptPath,target, sizeof(luaScriptPath)); - luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE,luaScriptPath,".lua"); + luaScriptPathJ= ScanForConfig(dirList, CTL_SCAN_RECURSIVE,luaScriptPath,".lua"); } for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); @@ -988,8 +989,6 @@ static const luaL_Reg afbFunction[] = { // Load Lua Interpreter int LuaConfigLoad () { - - // open a new LUA interpretor luaState = luaL_newstate(); if (!luaState) { @@ -1029,8 +1028,8 @@ int LuaConfigExec () { strncat (fullprefix, GetBinderName(), sizeof(fullprefix)); strncat (fullprefix, "-", sizeof(fullprefix)); - const char *dirList= getenv("CONTROL_LUA_PATH"); - if (!dirList) dirList=CONTROL_LUA_PATH; + const char *dirList = getenv("CONTROL_LUA_PATH"); + if (!dirList) dirList = strncat(GetBindingDirPath(), "/data", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1); // special case for no lua even when avaliable if (!strcasecmp ("/dev/null", dirList)) { @@ -1073,7 +1072,7 @@ int LuaConfigExec () { AFB_WARNING ("POLICY-INIT:WARNING (setenv CONTROL_LUA_PATH) No LUA '%s*.lua' in '%s'", fullprefix, dirList); } - AFB_DEBUG ("Audio control-LUA Init Done"); + AFB_DEBUG("Control-LUA Init Done"); return 0; OnErrorExit: diff --git a/controller/ctl-lua.h b/controller/ctl-lua.h index 2a85543..2fbebf5 100644 --- a/controller/ctl-lua.h +++ b/controller/ctl-lua.h @@ -25,6 +25,10 @@ #define _GNU_SOURCE #endif +#ifdef __cplusplus +extern "C" { +#endif + // prefix start debug script #ifndef CONTROL_DOSCRIPT_PRE #define CONTROL_DOSCRIPT_PRE "debug" @@ -35,11 +39,6 @@ #define CONTROL_LUA_EVENT "luaevt" #endif -// default use same search path for config.json and script.lua -#ifndef CONTROL_LUA_PATH -#define CONTROL_LUA_PATH CONTROL_CONFIG_PATH -#endif - #define AFB_BINDING_VERSION 2 #include @@ -65,7 +64,7 @@ typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunction #define CTLP_LUALOAD Lua2cWrapperT Lua2cWrap; #define CTLP_LUA2C(FuncName, label,argsJ, context) static int FuncName(char*label,json_object*argsJ);\ - int lua2c_ ## FuncName(lua_State* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(FuncName), FuncName, PLUGIN_NAME));};\ + 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 { @@ -74,7 +73,6 @@ typedef enum { LUA_DOSCRIPT, } LuaDoActionT; - int LuaConfigLoad(); int LuaConfigExec(); void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count); @@ -85,4 +83,8 @@ void ctlapi_lua_dostring (afb_req request); void ctlapi_lua_doscript (afb_req request); +#ifdef __cplusplus +} +#endif + #endif diff --git a/controller/ctl-plugin.c b/controller/ctl-plugin.c index d982b79..550924f 100644 --- a/controller/ctl-plugin.c +++ b/controller/ctl-plugin.c @@ -25,14 +25,6 @@ #include #include -#ifdef CONTROL_SUPPORT_LUA -#include "ctl-lua.h" -#else -typedef struct lua_State lua_State; -typedef void *Lua2cFunctionT; -typedef void *Lua2cWrapperT; -#endif - #include "ctl-config.h" static CtlPluginT *ctlPlugins=NULL; diff --git a/controller/ctl-plugin.h b/controller/ctl-plugin.h index 1c772c7..7934d8d 100644 --- a/controller/ctl-plugin.h +++ b/controller/ctl-plugin.h @@ -20,6 +20,10 @@ #ifndef _CTL_PLUGIN_INCLUDE_ #define _CTL_PLUGIN_INCLUDE_ +#ifdef __cplusplus +extern "C" { +#endif + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -70,4 +74,8 @@ typedef void*(*DispatchPluginInstallCbT)(CtlPluginT *plugin, void* handle); #define CTLP_ONLOAD(plugin, handle) void* CtlPluginOnload(CtlPluginT *plugin, void* handle) #define CTLP_CAPI(funcname, source, argsJ, queryJ, context) int funcname(CtlSourceT *source, json_object* argsJ, json_object* queryJ, void* context) +#ifdef __cplusplus +} +#endif + #endif /* _CTL_PLUGIN_INCLUDE_ */ diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9145b57..c0d7225 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -16,6 +16,29 @@ # limitations under the License. ########################################################################### +PROJECT_TARGET_ADD(lua2c-interface) + + # Define targets + ADD_LIBRARY(${TARGET_NAME} MODULE ${TARGET_NAME}.c) + + # Alsa Plugin properties + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "PLUGIN" + PREFIX "" + SUFFIX ".ctlso" + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + afb-utilities + ${link_libraries} + ) + + target_include_directories(${TARGET_NAME} + PRIVATE "../controller" + PRIVATE "../signal-composer-binding") + PROJECT_TARGET_ADD(low-can) # Define targets @@ -59,5 +82,5 @@ PROJECT_TARGET_ADD(gps) ) target_include_directories(${TARGET_NAME} - PRIVATE "../controller" - PRIVATE "../signal-composer-binding") + PRIVATE "../controller" + PRIVATE "../signal-composer-binding") diff --git a/plugins/low-can.c b/plugins/low-can.c deleted file mode 100644 index 86f0f5c..0000000 --- a/plugins/low-can.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Romain Forlot - * - * 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 // needed for vasprintf - -#define AFB_BINDING_VERSION 2 -#include -#include -#include -#include -#include - -#include "ctl-plugin.h" -#include "wrap-json.h" - -CTLP_REGISTER("low-can"); - -typedef struct { - bool door; - bool window; -} doorT; - -typedef struct { - doorT* front_left; - doorT* front_right; - doorT* rear_left; - doorT* rear_right; -} allDoorsCtxT; - -// Call at initialisation time -CTLP_ONLOAD(plugin, api) { - allDoorsCtxT *allDoorCtx = (allDoorsCtxT*)calloc (1, sizeof(allDoorsCtxT)); - memset(allDoorCtx, 0, sizeof(allDoorsCtxT)); - - AFB_NOTICE ("Low-can plugin: label='%s' version='%s' info='%s'", plugin->label, plugin->version, plugin->info); - return (void*)allDoorCtx; -} - -CTLP_CAPI (subscribeToLow, source, argsJ, eventJ, context) { - json_object* signalArrayJ = NULL, *subscribeArgsJ = NULL, *subscribeFilterJ = NULL, *responseJ = NULL; - const char* unit = NULL; - double frequency = 0; - int err = 0; - - err = wrap_json_unpack(eventJ, "{so,s?s,s?F !}", - "signal", &signalArrayJ, - "unit", &unit, - "frequency", &frequency); - if(err) - { - AFB_ERROR("Problem to unpack JSON object eventJ: %s", - json_object_to_json_string(eventJ)); - return err; - } - - if(frequency > 0) - { - wrap_json_pack(&subscribeFilterJ, "{sf}", "frequency", frequency); - } - - for (int idx = 0; idx < json_object_array_length(signalArrayJ); idx++) - { - json_object* aSignalJ = json_object_array_get_idx(signalArrayJ, idx); - err = wrap_json_pack(&subscribeArgsJ, "{ss, so*}", - "event", json_object_get_string(aSignalJ), - "filter", subscribeFilterJ); - if(err) - { - AFB_ERROR("Error building subscription query object"); - return err; - } - AFB_DEBUG("Calling subscribe with %s", json_object_to_json_string_ext(subscribeArgsJ, JSON_C_TO_STRING_PRETTY)); - err = afb_service_call_sync("low-can", "subscribe", subscribeArgsJ, &responseJ); - if(err) - { - AFB_ERROR("Can't find api 'low-can'"); - return err; - } - } - - return err; -} - -CTLP_CAPI (isOpen, source, argsJ, eventJ, context) { - - const char* eventName; - json_object *eventStatus = NULL; - long long int *timestamp = NULL; - allDoorsCtxT *ctx=(allDoorsCtxT*)context; - - AFB_DEBUG("Here is the situation: source:%s, args:%s, event:%s,\n fld: %s, flw: %s, frd: %s, frw: %s, rld: %s, rlw: %s, rrd: %s, rrw: %s", - source->label, - json_object_to_json_string(argsJ), - json_object_to_json_string(eventJ), - ctx->front_left->door ? "true":"false", - ctx->front_left->window ? "true":"false", - ctx->front_right->door ? "true":"false", - ctx->front_right->window ? "true":"false", - ctx->rear_left->door ? "true":"false", - ctx->rear_left->window ? "true":"false", - ctx->rear_right->door ? "true":"false", - ctx->rear_right->window ? "true":"false" - ); - - int err = wrap_json_unpack(eventJ, "{ss,sb,s?F}", - "event", &eventName, - "value", &eventStatus, - "timestamp", ×tamp); - if(err) - { - AFB_ERROR("Error parsing event %s", json_object_to_json_string(eventJ)); - return -1; - } - - if(strcasestr(eventName, "front_left")) - { - if(strcasestr(eventName, "door")) {ctx->front_left->door = eventStatus;} - else if(strcasestr(eventName, "window")) {ctx->front_left->window = eventStatus;} - else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} - } - else if(strcasestr(eventName, "front_right")) - { - if(strcasestr(eventName, "door")) {ctx->front_right->door = eventStatus;} - else if(strcasestr(eventName, "window")) {ctx->front_right->window = eventStatus;} - else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} - } - else if(strcasestr(eventName, "rear_left")) - { - if(strcasestr(eventName, "door")) {ctx->rear_left->door = eventStatus;} - else if(strcasestr(eventName, "window")) {ctx->rear_left->window = eventStatus;} - else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} - } - else if(strcasestr(eventName, "rear_right")) - { - if(strcasestr(eventName, "door")) {ctx->rear_right->door = eventStatus;} - else if(strcasestr(eventName, "window")) {ctx->rear_right->window = eventStatus;} - else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} - } - else {AFB_WARNING("Unexpected behavior, this '%s' is not a door ! ", json_object_to_json_string(eventJ));} - - return 0; -} diff --git a/plugins/low-can.cpp b/plugins/low-can.cpp index 8b573ba..7fc5020 100644 --- a/plugins/low-can.cpp +++ b/plugins/low-can.cpp @@ -26,7 +26,6 @@ #include "ctl-plugin.h" #include "wrap-json.h" - #include "signal-composer.hpp" extern "C" @@ -115,7 +114,7 @@ CTLP_CAPI (subscribeToLow, source, argsJ, eventJ, context) { err = afb_service_call_sync("low-can", "subscribe", subscribeArgsJ, &responseJ); if(err) { - AFB_ERROR("Can't find api 'low-can'"); + AFB_ERROR("Subscribe to 'low-can/%s' %s", lowEvent.c_str(), json_object_to_json_string(responseJ)); return err; } diff --git a/plugins/lua2c-interface.c b/plugins/lua2c-interface.c new file mode 100644 index 0000000..d57cfbd --- /dev/null +++ b/plugins/lua2c-interface.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Romain Forlot + * + * 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 // needed for vasprintf + +#define AFB_BINDING_VERSION 2 +#include +#include +#include +#include +#include + +#include "ctl-config.h" +#include "wrap-json.h" + +CTLP_LUALOAD +CTLP_REGISTER("lua2c-interface"); + +typedef struct { + struct pluginCBT* pluginHandle; +} lowCANCtxT; + +// Call at initialisation time +CTLP_ONLOAD(plugin, handle) { + lowCANCtxT *pluginCtx= (lowCANCtxT*)calloc (1, sizeof(lowCANCtxT)); + pluginCtx->pluginHandle = (struct pluginCBT*)handle; + + AFB_NOTICE ("Low-can plugin: label='%s' version='%s' info='%s'", + plugin->label, + plugin->version, + plugin->info); + + return (void*)pluginCtx; +} +/* +CTLP_LUA2C (LUAsetSignalValue, label, argsJ, context) +{ + AFB_NOTICE("label: %s, argsJ: %s", label, json_object_to_json_string(argsJ)); + return 0; +} +*/ diff --git a/signal-composer-binding/signal-composer-binding.cpp b/signal-composer-binding/signal-composer-binding.cpp index 4f12150..269eaba 100644 --- a/signal-composer-binding/signal-composer-binding.cpp +++ b/signal-composer-binding/signal-composer-binding.cpp @@ -20,14 +20,16 @@ // afb-utilities #include #include -// controller -#include #include "signal-composer-binding.hpp" #include "signal-composer-apidef.h" #include "signal-composer.hpp" -/// @brief callback for receiving message from low binding. Treatment itself is made in SigComp class. +/// @brief callback for receiving message from low bindings. This will callback +/// an action defined in the configuration files depending on the event received +/// +/// @param[in] event - event name +/// @param[in] object - eventual data that comes with the event void onEvent(const char *event, json_object *object) { AFB_DEBUG("Received event json: %s", json_object_to_json_string(object)); @@ -130,10 +132,6 @@ int loadConf() bindingApp& bApp = bindingApp::instance(); err = bApp.loadConfig(rootdir); - #ifdef CONTROL_SUPPORT_LUA - err += LuaConfigLoad(); - #endif - return err; } diff --git a/signal-composer-binding/signal-composer.cpp b/signal-composer-binding/signal-composer.cpp index 151de6c..2e4f221 100644 --- a/signal-composer-binding/signal-composer.cpp +++ b/signal-composer-binding/signal-composer.cpp @@ -84,6 +84,15 @@ SourceAPI* bindingApp::getSourceAPI(const std::string& api) } return nullptr; } +int bindingApp::initSourcesAPI() +{ + int err = 0; + for(auto& src: sourcesListV_) + { + err += src.init(); + } + return err; +} std::vector bindingApp::parseURI(const std::string& uri) { @@ -123,7 +132,7 @@ CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* act std::string fName = std::string(function).substr(6); wrap_json_pack(&action, "{ss,ss,so*}", "label", name.c_str(), - "lua", fName, + "lua", fName.c_str(), "args", functionArgsJ); } else if(startsWith(function, "api://")) @@ -205,13 +214,13 @@ int bindingApp::loadSourcesAPI(CtlSectionT* section, json_object *sourcesJ) { int err = 0; bindingApp& bApp = instance(); - json_object *sigCompJ = nullptr; - // add the signal composer itself as source if(sourcesJ) { + json_object *sigCompJ = nullptr; + // add the signal composer itself as source wrap_json_pack(&sigCompJ, "{ss,ss}", - "api", "signal-composer", + "api", afbBindingV2.api, "info", "Api on behalf the virtual signals are sent"); json_object_array_add(sourcesJ, sigCompJ); @@ -232,7 +241,9 @@ int bindingApp::loadSourcesAPI(CtlSectionT* section, json_object *sourcesJ) if ((err = bApp.loadOneSourceAPI(sourcesJ))) return err; if (sigCompJ && (err = bApp.loadOneSourceAPI(sigCompJ))) return err; } -} + } + else + {err += bindingApp::instance().initSourcesAPI();} return err; } diff --git a/signal-composer-binding/signal-composer.hpp b/signal-composer-binding/signal-composer.hpp index 4050700..689f107 100644 --- a/signal-composer-binding/signal-composer.hpp +++ b/signal-composer-binding/signal-composer.hpp @@ -49,6 +49,7 @@ public: int loadSignals(json_object* signalsJ); CtlConfigT* ctlConfig(); + int initSourcesAPI(); std::vector> getAllSignals(); SourceAPI* getSourceAPI(const std::string& api); std::shared_ptr searchSignal(const std::string& aName); diff --git a/signal-composer-binding/signal.cpp b/signal-composer-binding/signal.cpp index 1679a6f..309a156 100644 --- a/signal-composer-binding/signal.cpp +++ b/signal-composer-binding/signal.cpp @@ -182,7 +182,7 @@ void Signal::attachToSourceSignals(bindingApp& bApp) /// @brief Call update() method on observer Signal with /// current Signal timestamp and value -void Signal::notify() +void Signal::notify() const { for (int i = 0; i < Observers_.size(); ++i) Observers_[i]->update(timestamp_, value_); @@ -194,7 +194,7 @@ void Signal::notify() /// @param[in] origId - name of the origine of the recursion check /// /// @return 0 if no infinite loop detected, -1 if not. -int Signal::recursionCheck(const std::string& origId) +int Signal::recursionCheck(const std::string& origId) const { for (const auto& obs: Observers_) { @@ -214,7 +214,7 @@ int Signal::recursionCheck(const std::string& origId) /// then trigger the check against the following eventuals observers /// /// @return 0 if no infinite loop detected, -1 if not. -int Signal::recursionCheck() +int Signal::recursionCheck() const { for (const auto& obs: Observers_) { diff --git a/signal-composer-binding/signal.hpp b/signal-composer-binding/signal.hpp index 4e078fc..c029a64 100644 --- a/signal-composer-binding/signal.hpp +++ b/signal-composer-binding/signal.hpp @@ -49,13 +49,14 @@ private: std::vector Observers_; - void notify(); + void notify() const; void attach(Signal *obs); - int recursionCheck(const std::string& origId); + int recursionCheck(const std::string& origId) const; public: Signal(const std::string& id, const std::string& event, std::vector& depends, const std::string& unit, double frequency, CtlActionT* onReceived, json_object* getSignalsArgs); Signal(const std::string& id, std::vector& depends, const std::string& unit, double frequency, CtlActionT* onReceived); + explicit operator bool() const; bool operator==(const Signal& other) const; bool operator==(const std::string& aName) const; @@ -72,5 +73,5 @@ public: double minimum(int seconds = 0) const; double maximum(int seconds = 0) const; struct SignalValue last() const; - int recursionCheck(); + int recursionCheck() const; }; diff --git a/signal-composer-binding/source.cpp b/signal-composer-binding/source.cpp index 1f5d588..2f4ab03 100644 --- a/signal-composer-binding/source.cpp +++ b/signal-composer-binding/source.cpp @@ -16,6 +16,7 @@ */ #include "source.hpp" +#include "signal-composer.hpp" SourceAPI::SourceAPI() {} @@ -24,6 +25,18 @@ SourceAPI::SourceAPI(const std::string& api, const std::string& info, CtlActionT api_(api), info_(info), init_(init), getSignals_(getSignals) {} +int SourceAPI::init() +{ + if(init_) + {return ActionExecOne(init_, nullptr);} + else if(api_ == afbBindingV2.api) + { + api_ = bindingApp::instance().ctlConfig()->api; + } + + return 0; +} + std::string SourceAPI::api() const { return api_; @@ -71,7 +84,8 @@ int SourceAPI::makeSubscription() } err += sig.second ? 0:ActionExecOne(getSignals_, signalJ); if(err) - {AFB_WARNING("Fails to subscribe to signal %s", sig.first->id().c_str());} + {AFB_WARNING("Fails to subscribe to signal '%s/%s'", + api_.c_str(), sig.first->id().c_str());} else {sig.second = true;} } diff --git a/signal-composer-binding/source.hpp b/signal-composer-binding/source.hpp index 560a137..a995b07 100644 --- a/signal-composer-binding/source.hpp +++ b/signal-composer-binding/source.hpp @@ -34,6 +34,7 @@ public: SourceAPI(); SourceAPI(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal); + int init(); std::string api() const; void addSignal(const std::string& id, const std::string& event, std::vector& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived, json_object* getSignalsArgs); -- cgit 1.2.3-korg