diff options
24 files changed, 603 insertions, 383 deletions
diff --git a/afb-utilities b/afb-utilities -Subproject fdf2c27980f756cf63890576d80eef20b78fe98 +Subproject 49a99fef3e1e1ea0ecd7f131fd56da4c54bcd14 diff --git a/conf.d/app-templates b/conf.d/app-templates -Subproject 784e0e5a0624185a2190a6c979cf1c7440645c4 +Subproject 908a0372d53c74a037da3debe1e276a214343c4 diff --git a/conf.d/project/etc/init-daemon.json b/conf.d/project/etc/init-daemon.json new file mode 100644 index 0000000..dc18f7e --- /dev/null +++ b/conf.d/project/etc/init-daemon.json @@ -0,0 +1,19 @@ +{ + "$schema": "ToBeDone", + "metadata": { + "label": "Signal Composer", + "version": "1.0", + "api": "signal-composer", + "info": "Signal composer Configuration", + "require": ["low-can"], + "files": ["sources", "sig-doors"] + }, + "plugins": [ + { + "label": "Door handle", + "version": "1.0", + "info": "Manage all doors and windows status", + "basename": "doors" + } + ] +} diff --git a/conf.d/project/etc/sig-doors.json b/conf.d/project/etc/sig-doors.json index e93745e..bc26296 100644 --- a/conf.d/project/etc/sig-doors.json +++ b/conf.d/project/etc/sig-doors.json @@ -1,83 +1,60 @@ { "signals": [ { - "id": "rear_left_windows", - "source": "low-can/messages.windows.rear_left.open", - "class": "state", - "onReceived": { - "function": "_Door_opened", - "args": { - "evtname": "messages.windows.rear_left.open" - } - } + "id": "rear_left_window", + "source": "low-can/messages.windows.rear_left.open" }, { "id": "rear_left_door", - "source": "low-can/messages.doors.rear_left.open", - "class": "state", - "onReceived": { - "function": "_Door_opened", - "args": { - "evtname": "messages.doors.rear_left.open" - } - } + "source": "low-can/messages.doors.rear_left.open" }, { - "id": "rear_left", - "source": [ - "rear_left_windows", - "rear_left_doors" - ], - "class": "state", - "onReceived": { - "function": "_Door_opened", - "args": { - "ojoi": "pok" - } - } + "id": "rear_right_window", + "source": "low-can/messages.windows.rear_right.open" + }, + { + "id": "rear_right_door", + "source": "low-can/messages.doors.rear_right.open" + }, + { + "id": "front_left_window", + "source": "low-can/messages.windows.front_left.open" + }, + { + "id": "front_left_door", + "source": "low-can/messages.doors.front_left.open" }, { "id": "front_right_window", - "source": "low-can/messages.windows.front_right.open", - "class": "state", - "onReceived": { - "function": "_Door_opened", - "args": { - "evtname": "messages.windows.front_right.open" - } - } + "source": "low-can/messages.windows.front_right.open" }, { - "id": "rear_right_door", - "source": "low-can/messages.doors.rear_right.open", - "class": "state", - "onReceived": { - "function": "_Door_opened", - "args": { - "evtname": "messages.doors.rear_right.open" - } - } + "id": "front_right_door", + "source": "low-can/messages.doors.front_right.open" }, { - "id": "rear_right_window", - "source": "low-can/messages.windows.rear_right.open", - "class": "state", + "id": "rear_left", + "source": [ + "rear_left_window", + "rear_left_door" + ], "onReceived": { - "function": "_Door_opened", + "plugin": "Door handle", + "function": "isOpen", "args": { - "evtname": "messages.windows.rear_right.open" + "ojoi": "pok" } } }, { "id": "rear_right", "source": [ - "rear_right_doors", - "rear_right_windows" + "rear_right_door", + "rear_right_window" ], - "class": "state", "onReceived": { - "function": "_Complete_Door", + "plugin": "Door handle", + "function": "isOpen", "args": {} } }, @@ -85,41 +62,41 @@ "id": "front_left", "source": [ "front_left_door", - "front_left_windows" + "front_left_window" ], - "class": "state", "onReceived": { - "function": "_Complete_Door", + "plugin": "Door handle", + "function": "isOpen", "args": {} } }, { "id": "front_right", "source": [ - "front_right_doors", - "front_right_windows" + "front_right_door", + "front_right_window" ], - "class": "state", "onReceived": { - "function": "_Complete_Door", + "plugin": "Door handle", + "function": "isOpen", "args": {} } }, { "id": "all_doors", "source": [ - "front_left_doors", - "front_left_windows", - "front_right_doors", - "front_right_windows", - "rear_left_doors", - "rear_left_windows", - "rear_right_doors", - "rear_right_windows" + "front_left_door", + "front_left_window", + "front_right_door", + "front_right_window", + "rear_left_door", + "rear_left_window", + "rear_right_door", + "rear_right_window" ], - "class": "state", "onReceived": { - "function": "_Door_opened", + "plugin": "Door handle", + "function": "isOpen", "args": { "evtname": "doors.open" } diff --git a/conf.d/project/etc/sig-sources.json b/conf.d/project/etc/sig-sources.json deleted file mode 100644 index 1142196..0000000 --- a/conf.d/project/etc/sig-sources.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "$schema": "ToBeDone", - "metadata": { - "label": "signal-composer", - "info": "Signal composer Configuration", - "name": "afb-signal-composer", - "version": "1.0" - }, - "sources": [ - { - "api": "low-can", - "info": "Low level binding to handle CAN bus communications", - "init": { - "function": "c/lua (depend on name) function to initialize binding", - "args": { - "arg1": "first argument" - } - }, - "getSignal": { - "function": "c/lua (depend on name) function to get signals", - "args": { - "arg": "first argument" - } - } - }, { - "api": "gps", - "info": "Low level binding which retrieve Satellite positionning values", - "actions": [{ - "label": "init", - "function": "c/lua (depend on name) function to initialize binding", - "args": { - "arg": "first argument" - } - }, { - "label": "getSignal", - "function": "c/lua (depend on name) function to get signals", - "args": { - "arg": "first argument" - } - }] - }, { - "api": "mraa", - "info": "Low level binding which retrieve different values from several sensors like gyroscope, accelerometer, etc", - "actions": [{ - "label": "init", - "function": "c/lua (depend on name) function to initialize binding", - "args": { - "arg": "first argument" - } - }, { - "label": "getSignal", - "function": "c/lua (depend on name) function to get signals", - "args": { - "arg": "first argument" - } - }] - } - ] -} diff --git a/conf.d/project/etc/sources.json b/conf.d/project/etc/sources.json new file mode 100644 index 0000000..a70da50 --- /dev/null +++ b/conf.d/project/etc/sources.json @@ -0,0 +1,50 @@ +{ + "sources": [ + { + "api": "low-can", + "info": "Low level binding to handle CAN bus communications", + "init": { + "function": "low-can/subscribe", + "args": { + "event": "message*" + } + }, + "getSignal": { + "function": "_LUA_Simple_Echo_Args", + "args": { + "arg": "first argument" + } + } + }, { + "api": "gps", + "info": "Low level binding which retrieve Satellite positionning values", + "init": { + "function": "_LUA_Simple_Echo_Args", + "args": { + "arg1": "first argument" + } + }, + "getSignal": { + "function": "_LUA_Simple_Echo_Args", + "args": { + "arg": "first argument" + } + } + }, { + "api": "mraa", + "info": "Low level binding which retrieve different values from several sensors like gyroscope, accelerometer, etc", + "init": { + "function": "_LUA_Simple_Echo_Args", + "args": { + "arg1": "first argument" + } + }, + "getSignal": { + "function": "_LUA_Simple_Echo_Args", + "args": { + "arg": "first argument" + } + } + } + ] +} diff --git a/conf.d/project/lua.d/onload-daemon-04-oncall.lua b/conf.d/project/lua.d/onload-daemon-04-oncall.lua index b450932..7c0e9bc 100644 --- a/conf.d/project/lua.d/onload-daemon-04-oncall.lua +++ b/conf.d/project/lua.d/onload-daemon-04-oncall.lua @@ -22,7 +22,7 @@ _count=0 -- Display receive arguments and echo them to caller -function _Simple_Echo_Args (request, args) +function _LUA_Simple_Echo_Args (request, args) _count=_count+1 AFB:notice("LUA OnCall Echo Args count=%d args=%s", count, args) diff --git a/controller/ctl-config.c b/controller/ctl-config.c index 95f6db8..948f0d1 100644 --- a/controller/ctl-config.c +++ b/controller/ctl-config.c @@ -28,12 +28,16 @@ // Load control config file -char* CtlConfigSearch(const char *dirList) { +char* CtlConfigSearch(const char *dirList, const char* fileName) { int index; char controlFile [CONTROL_MAXPATH_LEN]; - strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN); - strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); + if(fileName) { + strncpy(controlFile, fileName, CONTROL_MAXPATH_LEN); + } else { + strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN); + strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); + } // search for default dispatch config file json_object* responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, controlFile, ".json"); @@ -97,9 +101,6 @@ 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) { @@ -112,18 +113,22 @@ CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections) { if (err) goto OnErrorExit; #endif - // Search for config in filepath - filepath = CtlConfigSearch(filepath); - - if (!filepath) { - AFB_ERROR("CTL-LOAD-CONFIG No JSON Config found invalid JSON %s ", filepath); - goto OnErrorExit; + json_object* loadJSON(const char* fileName) + { + // Search for config in filepath + const char* filepathFound = CtlConfigSearch(filepath, fileName); + if(!filepathFound) + { + AFB_ERROR("CTL-LOAD-CONFIG No JSON Config found in %s", filepath); + return NULL; + } + return json_object_from_file(filepathFound); } // Load JSON file - ctlConfigJ = json_object_from_file(filepath); + ctlConfigJ = loadJSON(NULL); if (!ctlConfigJ) { - AFB_ERROR("CTL-LOAD-CONFIG Not invalid JSON %s ", filepath); + AFB_ERROR("CTL-LOAD-CONFIG Invalid JSON %s ", filepath); goto OnErrorExit; } @@ -132,9 +137,13 @@ CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections) { json_object *metadataJ; int done = json_object_object_get_ex(ctlConfigJ, "metadata", &metadataJ); if (done) { - CtlConfigT *ctlConfig = calloc(1, sizeof (CtlConfigT)); - err = wrap_json_unpack(metadataJ, "{ss,ss,ss,s?s,s?o !}", "label", &ctlConfig->label, "version", &ctlConfig->version - , "api", &ctlConfig->api, "info", &ctlConfig->info, "require", &ctlConfig->requireJ); + err = wrap_json_unpack(metadataJ, "{ss,ss,ss,s?s,s?o,s?o !}", + "label", &ctlConfig->label, + "version", &ctlConfig->version, + "api", &ctlConfig->api, + "info", &ctlConfig->info, + "require", &ctlConfig->requireJ, + "files",&ctlConfig->filesJ); if (err) { AFB_ERROR("CTL-LOAD-CONFIG:METADATA Missing something label|api|version|[info]|[require] in:\n-- %s", json_object_get_string(metadataJ)); goto OnErrorExit; @@ -145,22 +154,52 @@ CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections) { err = afb_daemon_rename_api(ctlConfig->api); if (err) AFB_WARNING("Fail to rename api to:%s", ctlConfig->api); } - } //load config sections err = 0; ctlConfig->sections = sections; + for (int idx = 0; sections[idx].key != NULL; idx++) { json_object * sectionJ; int done = json_object_object_get_ex(ctlConfigJ, sections[idx].key, §ionJ); if (!done) { - AFB_ERROR("CtlConfigLoad: fail to find '%s' section in config '%s'", sections[idx].key, filepath); - err++; + json_object* configJ = NULL; + const char* fileName; + AFB_DEBUG("CtlConfigLoad: fail to find '%s' section in config '%s'. Searching deeper", sections[idx].key, filepath); + if (json_object_get_type(ctlConfig->filesJ) == json_type_array) { + int filesEnd = json_object_array_length(ctlConfig->filesJ); + for (int jdx = 0; jdx < filesEnd; jdx++) { + fileName = json_object_get_string(json_object_array_get_idx(ctlConfig->filesJ, jdx)); + configJ = loadJSON(fileName); + if(json_object_object_get_ex(configJ, sections[idx].key, §ionJ)) + { + const char* k = sections[idx].key; + err += sections[idx].loadCB(§ions[idx], sectionJ); + done++; + } + } + if(!done) { + AFB_ERROR("CtlConfigLoad: fail to find '%s' section in config '%s' with '%s' in its name", sections[idx].key, filepath, fileName); + err++; + } + if(err) {goto OnErrorExit;} + } else { + fileName = json_object_get_string(ctlConfig->filesJ); + configJ = loadJSON(fileName); + if(json_object_object_get_ex(configJ, sections[idx].key, §ionJ)) { + err += sections[idx].loadCB(§ions[idx], sectionJ); + done++; + } + else { + AFB_ERROR("CtlConfigLoad: fail to find '%s' section in config '%s' with '%s' in its name", sections[idx].key, filepath, fileName); + err++; + } + if(err) {goto OnErrorExit;} + } } else { err += sections[idx].loadCB(§ions[idx], sectionJ); } - } if (err) goto OnErrorExit; diff --git a/controller/ctl-config.h b/controller/ctl-config.h index 3b39f53..7c3631c 100644 --- a/controller/ctl-config.h +++ b/controller/ctl-config.h @@ -75,11 +75,11 @@ typedef struct { } DispatchHandleT; typedef struct ConfigSectionS { - const char *key; - const char *label; - const char *info; - int (*loadCB)(struct ConfigSectionS *section, json_object *sectionJ); - void *handle; + const char *key; + const char *label; + const char *info; + int (*loadCB)(struct ConfigSectionS *section, json_object *sectionJ); + void *handle; } CtlSectionT; typedef struct { @@ -88,6 +88,7 @@ typedef struct { const char *info; const char *version; json_object *requireJ; + json_object *filesJ; CtlSectionT *sections; } CtlConfigT; diff --git a/controller/ctl-plugin.c b/controller/ctl-plugin.c index 748c78b..ae203af 100644 --- a/controller/ctl-plugin.c +++ b/controller/ctl-plugin.c @@ -44,8 +44,7 @@ int PluginGetCB (CtlActionT *action , json_object *callbackJ) { goto OnErrorExit; } - - int err = wrap_json_unpack(callbackJ, "{ss,ss,s?s,s?o!}", "plugin", &plugin, "function", &function, "args", &argsJ); + int err = wrap_json_unpack(callbackJ, "{ss,ss,s?o!}", "plugin", &plugin, "function", &function, "args", &argsJ); if (err) { AFB_ERROR("PluginGet missing plugin|function|[args] in %s", json_object_get_string(callbackJ)); goto OnErrorExit; @@ -87,7 +86,8 @@ STATIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT ca STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* handle) { json_object *lua2csJ = NULL, *actionsJ = NULL; - const char*ldSearchPath = NULL, *basename = NULL; + const char *basename = NULL; + char *ldSearchPath = NULL; void *dlHandle; @@ -95,15 +95,23 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han if (!pluginJ) return 0; int err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,s?s,ss,s?o,s?o!}", - "label", &ctlPlugin->label, "version", &ctlPlugin->version, "info", &ctlPlugin->info, "ldpath", &ldSearchPath, "basename", &basename, "lua2c", &lua2csJ, "actions", &actionsJ); + "label", &ctlPlugin->label, + "version", &ctlPlugin->version, + "info", &ctlPlugin->info, + "ldpath", &ldSearchPath, + "basename", &basename, + "lua2c", &lua2csJ, + "actions", &actionsJ); if (err) { AFB_ERROR("CTL-PLUGIN-LOADONE Plugin missing label|basename|version|[info]|[ldpath]|[lua2c]|[actions] in:\n-- %s", json_object_get_string(pluginJ)); goto OnErrorExit; } // if search path not in Json config file, then try default binding dir - ldSearchPath = getenv("CONTROL_PLUGIN_PATH"); - if (!ldSearchPath) ldSearchPath = strncat(GetBindingDirPath(), "/lib", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1); + if (!ldSearchPath) ldSearchPath = getenv("CONTROL_PLUGIN_PATH"); + if (!ldSearchPath) { + ldSearchPath = strncat(GetBindingDirPath(), "/lib", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1); + } // search for default policy config file json_object *pluginPathJ = ScanForConfig(ldSearchPath, CTL_SCAN_RECURSIVE, basename, CTL_PLUGIN_EXT); @@ -145,7 +153,7 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han // store dlopen handle to enable onload action at exec time ctlPlugin->dlHandle = dlHandle; - // Jose hack to make verbosity visible from sharelib + // Jose hack to make verbosity visible from sharedlib struct afb_binding_data_v2 *afbHidenData = dlsym(dlHandle, "afbBindingV2data"); if (afbHidenData) *afbHidenData = afbBindingV2data; @@ -208,7 +216,6 @@ OnErrorExit: return 1; } - int PluginConfig(CtlSectionT *section, json_object *pluginsJ) { int err=0; diff --git a/low-can/CMakeLists.txt b/low-can/CMakeLists.txt new file mode 100644 index 0000000..e1e1907 --- /dev/null +++ b/low-can/CMakeLists.txt @@ -0,0 +1,40 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Romain Forlot <romain.forlot@iot.bzh> +# +# 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. +########################################################################### + + + +PROJECT_TARGET_ADD(doors) + + # 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} + ) + + include_directories("../controller") diff --git a/low-can/doors.c b/low-can/doors.c new file mode 100644 index 0000000..ce0b0c9 --- /dev/null +++ b/low-can/doors.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Romain Forlot <romain.forlot@iot.bzh> + * + * 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 <afb/afb-binding.h> +#include <systemd/sd-event.h> +#include <json-c/json_object.h> +#include <stdbool.h> +#include <string.h> + +#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 door plugin: label='%s' version='%s' info='%s'", plugin->label, plugin->version, plugin->info); + return (void*)allDoorCtx; +} + +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/signal-composer-binding/CMakeLists.txt b/signal-composer-binding/CMakeLists.txt index 8757204..3d7130b 100644 --- a/signal-composer-binding/CMakeLists.txt +++ b/signal-composer-binding/CMakeLists.txt @@ -21,7 +21,7 @@ PROJECT_TARGET_ADD(signal-composer) # Define project Targets - add_library(${TARGET_NAME} MODULE ${TARGET_NAME}-binding.cpp ${TARGET_NAME}.cpp signal-composer.cpp source.cpp) + add_library(${TARGET_NAME} MODULE ${TARGET_NAME}-binding.cpp ${TARGET_NAME}.cpp source.cpp signal.cpp) # Binder exposes a unique public entry point SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES @@ -31,8 +31,9 @@ PROJECT_TARGET_ADD(signal-composer) OUTPUT_NAME ${TARGET_NAME} ) - - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ) # Library dependencies (include updates automatically) TARGET_LINK_LIBRARIES(${TARGET_NAME} diff --git a/signal-composer-binding/observer.hpp b/signal-composer-binding/observer.hpp deleted file mode 100644 index e4129c6..0000000 --- a/signal-composer-binding/observer.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#include <vector> - -class Observer -{ -public: - virtual void update(double timestamp, double value) = 0; -}; - -class Subject -{ - double timestamp_; - double value_; - std::vector<Observer*> m_views; -public: - void attach(Observer *obs) - { - m_views.push_back(obs); - } - void set_val(double timestamp, double value) - { - timestamp_ = timestamp; - value_ = value; - notify(); - } - void notify() - { - for (int i = 0; i < m_views.size(); ++i) - m_views[i]->update(timestamp_, value_); - } -}; diff --git a/signal-composer-binding/signal-composer-binding.cpp b/signal-composer-binding/signal-composer-binding.cpp index 90401f2..860de07 100644 --- a/signal-composer-binding/signal-composer-binding.cpp +++ b/signal-composer-binding/signal-composer-binding.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include <string> #include <string.h> // afb-utilities #include <wrap-json.h> @@ -29,6 +30,14 @@ /// @brief callback for receiving message from low binding. Treatment itself is made in SigComp class. void onEvent(const char *event, json_object *object) { + AFB_DEBUG("Received event json: %s", json_object_to_json_string(object)); + bindingApp& bApp = bindingApp::instance(); + + std::shared_ptr<Signal> sig = bApp.searchSignal(event); + if(sig != nullptr) + { + sig->onReceivedCB(object); + } } /// @brief entry point for client subscription request. Treatment itself is made in SigComp class. void subscribe(afb_req request) @@ -55,20 +64,18 @@ void loadConf(afb_req request) const char* confd; wrap_json_unpack(args, "{s:s}", "path", &confd); - int ret = 0; - if( ret == 0) + if(true) afb_req_success(request, NULL, NULL); else - afb_req_fail_f(request, "Loading configuration or subscription error", "Error code: %d", ret); + afb_req_fail_f(request, "Loading configuration or subscription error", "Error code: -1"); } /// @brief entry point for get requests. Treatment itself is made in SigComp class. void get(afb_req request) { - json_object *jobj; if(true) { - afb_req_success(request, jobj, NULL); + afb_req_success(request, NULL, NULL); } else { @@ -83,7 +90,7 @@ int loadConf() sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) -1); bindingApp& bApp = bindingApp::instance(); - bApp.loadConfig(rootdir); + ret = bApp.loadConfig(rootdir); #ifdef CONTROL_SUPPORT_LUA ret += LuaConfigLoad(); @@ -98,6 +105,10 @@ int execConf() int ret = CtlConfigExec(bApp.ctlConfig()); std::vector<std::shared_ptr<Signal>> allSignals = bApp.getAllSignals(); ssize_t sigCount = allSignals.size(); + for( std::shared_ptr<Signal>& sig: allSignals) + { + sig->attachToSources(bApp); + } for(auto& sig: allSignals) { diff --git a/signal-composer-binding/signal-composer-binding.hpp b/signal-composer-binding/signal-composer-binding.hpp index e73438b..8599a13 100644 --- a/signal-composer-binding/signal-composer-binding.hpp +++ b/signal-composer-binding/signal-composer-binding.hpp @@ -1,8 +1,5 @@ #pragma once -#include <systemd/sd-event.h> -#include <ctl-config.h> - extern "C" { #define AFB_BINDING_VERSION 2 diff --git a/signal-composer-binding/signal-composer.cpp b/signal-composer-binding/signal-composer.cpp index 6f629e1..a1300e3 100644 --- a/signal-composer-binding/signal-composer.cpp +++ b/signal-composer-binding/signal-composer.cpp @@ -15,16 +15,21 @@ * limitations under the License. */ +#include <string.h> + #include "signal-composer.hpp" CtlSectionT bindingApp::ctlSections_[] = { - [0]={.key="sources" ,.label = "sources", .info=nullptr, - .loadCB=loadSources, + [0]={.key="plugins" ,.label = "plugins", .info=nullptr, + .loadCB=PluginConfig, + .handle=nullptr}, + [1]={.key="sources" ,.label = "sources", .info=nullptr, + .loadCB=loadSourcesAPI, .handle=nullptr}, - [1]={.key="signals" , .label= "signals", .info=nullptr, + [2]={.key="signals" , .label= "signals", .info=nullptr, .loadCB=loadSignals, .handle=nullptr}, - [2]={.key=nullptr, .label=nullptr, .info=nullptr, + [3]={.key=nullptr, .label=nullptr, .info=nullptr, .loadCB=nullptr, .handle=nullptr} }; @@ -32,9 +37,16 @@ CtlSectionT bindingApp::ctlSections_[] = { bindingApp::bindingApp() {} -void bindingApp::loadConfig(const std::string& filepath) +bindingApp::~bindingApp() +{ + free(ctlConfig_); +} + +int bindingApp::loadConfig(const std::string& filepath) { ctlConfig_ = CtlConfigLoad(filepath.c_str(), ctlSections_); + if(ctlConfig_ != nullptr) {return 0;} + return -1; } bindingApp& bindingApp::instance() @@ -43,7 +55,7 @@ bindingApp& bindingApp::instance() return bApp; } -Source* bindingApp::getSource(const std::string& api) +SourceAPI* bindingApp::getSourceAPI(const std::string& api) { for(auto& source: sourcesList_) { @@ -53,46 +65,53 @@ Source* bindingApp::getSource(const std::string& api) return nullptr; } -CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* action) +CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* actionJ) { - json_object *functionArgsJ = nullptr; - const char* function; - - if(action && - wrap_json_unpack(action, "{ss,s?o !}", "function", &function, "args", &functionArgsJ)) + json_object *functionArgsJ = nullptr, *action = nullptr; + char *function; + const char *plugin; + + if(actionJ && + !wrap_json_unpack(actionJ, "{ss,s?s,s?o !}", "function", &function, + "plugin", &plugin, + "args", &functionArgsJ)) { - std::string functionS = function; - json_object* action = nullptr; - ssize_t sep; - if(functionS.find("lua") != std::string::npos) + action = nullptr; + if(::strcasestr(function, "lua")) { - wrap_json_pack(&action, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}", - "label", name, + wrap_json_pack(&action, "{ss,ss,so*}", + "label", name.c_str(), "lua", function, "args", functionArgsJ); } - else if( (sep = functionS.find_first_of("/")) != std::string::npos) + else if(strstr(function, "/")) { - std::string api = functionS.substr(0, sep); - std::string verb = functionS.substr(sep); - wrap_json_pack(&action, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}", - "label", name, + const char* api = strsep(&function, "/"); + //std::string api = functionS.substr(0, sep); + //std::string verb = functionS.substr(sep); + wrap_json_pack(&action, "{ss,ss,ss,so*}", + "label", name.c_str(), "api", api, - "verb", verb, + "verb", function, "args", functionArgsJ); } else { - wrap_json_pack(&action, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}", - "label", name, - "callback", function, - "args", functionArgsJ); + json_object *callbackJ = nullptr; + wrap_json_pack(&callbackJ, "{ss,ss,so*}", + "plugin", plugin, + "function", function, + "args", functionArgsJ); + wrap_json_pack(&action, "{ss,so}", + "label", name.c_str(), + "callback", callbackJ); } } - return ActionLoad(action); + if(action) {return ActionLoad(action);} + return nullptr; } -int bindingApp::loadOneSource(json_object* sourceJ) +int bindingApp::loadOneSourceAPI(json_object* sourceJ) { json_object *initJ = nullptr, *getSignalJ = nullptr; CtlActionT *initCtl, *getSignalCtl; @@ -109,44 +128,53 @@ int bindingApp::loadOneSource(json_object* sourceJ) return err; } - initCtl = convert2Action("init", initJ); - getSignalCtl =convert2Action("getSignal", getSignalJ); + if(ctlConfig_ && ctlConfig_->requireJ) + { + const char* requireS = json_object_to_json_string(ctlConfig_->requireJ); + if(!strcasestr(requireS, api)) + {AFB_WARNING("Caution! You don't specify the API source as required in the metadata section. This API '%s' may not be initialized", api);} + } - sourcesList_.push_back(Source(api, info, initCtl, getSignalCtl)); + if(initJ) {initCtl = convert2Action("init", initJ);} + if(getSignalJ) {getSignalCtl = convert2Action("getSignal", getSignalJ);} + + sourcesList_.push_back(SourceAPI(api, info, initCtl, getSignalCtl)); return err; } -int bindingApp::loadSources(CtlSectionT* section, json_object *sourcesJ) +int bindingApp::loadSourcesAPI(CtlSectionT* section, json_object *sourcesJ) { int err = 0; bindingApp& bApp = instance(); - // add the signal composer itself as source json_object *sigCompJ = nullptr; - wrap_json_pack(&sigCompJ, "{ss,ss,so,so !}", - "api", "signal-composer", - "info", "Api on behalf the virtual signals are sent", - "init", nullptr, - "getSignal", nullptr); - json_object_array_add(sourcesJ, sigCompJ); - - if (json_object_get_type(sourcesJ) == json_type_array) + // add the signal composer itself as source + if(sourcesJ) { - int count = json_object_array_length(sourcesJ); + wrap_json_pack(&sigCompJ, "{ss,ss}", + "api", "signal-composer", + "info", "Api on behalf the virtual signals are sent"); - for (int idx = 0; idx < count; idx++) + json_object_array_add(sourcesJ, sigCompJ); + + if (json_object_get_type(sourcesJ) == json_type_array) { - json_object *sourceJ = json_object_array_get_idx(sourcesJ, idx); - err = bApp.loadOneSource(sourceJ); - if (err) return err; + int count = json_object_array_length(sourcesJ); + + for (int idx = 0; idx < count; idx++) + { + json_object *sourceJ = json_object_array_get_idx(sourcesJ, idx); + err = bApp.loadOneSourceAPI(sourceJ); + if (err) return err; + } } - } - else - { - if ((err = bApp.loadOneSource(sourcesJ))) return err; - if ((err = bApp.loadOneSource(sigCompJ))) return err; - } + else + { + if ((err = bApp.loadOneSourceAPI(sourcesJ))) return err; + if (sigCompJ && (err = bApp.loadOneSourceAPI(sigCompJ))) return err; + } +} return err; } @@ -172,7 +200,7 @@ int bindingApp::loadOneSignal(json_object* signalJ) "onReceived", &onReceivedJ); if (err) { - AFB_ERROR("Missing something id|source|class|[unit]|[frequency]|onReceived in %s", json_object_get_string(signalJ)); + AFB_ERROR("Missing something id|source|[class]|[unit]|[frequency]|[onReceived] in %s", json_object_get_string(signalJ)); return err; } @@ -183,7 +211,7 @@ int bindingApp::loadOneSignal(json_object* signalJ) int count = json_object_array_length(sourcesJ); for(int i = 0; i < count; i++) { - std::string sourceStr = json_object_get_string(sourcesJ); + std::string sourceStr = json_object_get_string(json_object_array_get_idx(sourcesJ, i)); if( (sep = sourceStr.find("/")) != std::string::npos) { AFB_ERROR("Signal composition needs to use signal 'id', don't use full low level signal name"); @@ -203,12 +231,13 @@ int bindingApp::loadOneSignal(json_object* signalJ) } // Set default sClass is not specified - sClass = "state"; + sClass = !sClass ? "state" : sClass; + unit = !unit ? "" : unit; // Get an action handler onReceivedCtl = convert2Action("onReceived", onReceivedJ); - Source* src = getSource(api); + SourceAPI* src = getSourceAPI(api) ? getSourceAPI(api):getSourceAPI("signal-composer"); if( src != nullptr) {src->addSignal(id, sourcesV, sClass, unit, frequency, onReceivedCtl);} else @@ -239,6 +268,28 @@ int bindingApp::loadSignals(CtlSectionT* section, json_object *signalsJ) return err; } +std::shared_ptr<Signal> bindingApp::searchSignal(const std::string& aName) +{ + std::string api; + size_t sep = aName.find_first_of("/"); + if(sep != std::string::npos) + { + api = aName.substr(0, sep); + SourceAPI* source = getSourceAPI(api); + return source->searchSignal(aName); + } + else + { + std::vector<std::shared_ptr<Signal>> allSignals = getAllSignals(); + for (std::shared_ptr<Signal>& sig : allSignals) + { + if(sig->id() == aName) + {return sig;} + } + } + return nullptr; +} + std::vector<std::shared_ptr<Signal>> bindingApp::getAllSignals() { std::vector<std::shared_ptr<Signal>> allSignals; diff --git a/signal-composer-binding/signal-composer.hpp b/signal-composer-binding/signal-composer.hpp index 44b958f..8affc7a 100644 --- a/signal-composer-binding/signal-composer.hpp +++ b/signal-composer-binding/signal-composer.hpp @@ -19,12 +19,8 @@ #include <memory> #include <vector> #include <string> -#include <ctl-config.h> -#include <json-c/json.h> -#include <systemd/sd-event.h> #include "source.hpp" -#include "signal-composer-binding.hpp" class bindingApp { @@ -32,7 +28,7 @@ private: CtlConfigT* ctlConfig_; static CtlSectionT ctlSections_[]; ///< Config Section definition (note: controls section index should match handle retrieval in) - std::vector<Source> sourcesList_; + std::vector<SourceAPI> sourcesList_; explicit bindingApp(const std::string& filepath); bindingApp(); @@ -40,19 +36,19 @@ private: CtlActionT* convert2Action(const std::string& name, json_object* action); - int loadOneSource(json_object* sourcesJ); - static int loadSources(CtlSectionT* section, json_object *sectionJ); + int loadOneSourceAPI(json_object* sourcesJ); + static int loadSourcesAPI(CtlSectionT* section, json_object *sectionJ); int loadOneSignal(json_object* signalsJ); static int loadSignals(CtlSectionT* section, json_object *sectionJ); - Source* getSource(const std::string& api); - public: static bindingApp& instance(); - void loadConfig(const std::string& filepath); - void loadSignalsFile(std::string signalsFile); + int loadConfig(const std::string& filepath); + //void loadSignalsFile(std::string signalsFile); + SourceAPI* getSourceAPI(const std::string& api); + std::shared_ptr<Signal> searchSignal(const std::string& aName); std::vector<std::shared_ptr<Signal>> getAllSignals(); CtlConfigT* ctlConfig(); }; diff --git a/signal-composer-binding/signal-conf.cpp b/signal-composer-binding/signal-conf.cpp deleted file mode 100644 index 73f2450..0000000 --- a/signal-composer-binding/signal-conf.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2015, 2016 "IoT.bzh" - * Author "Romain Forlot" <romain.forlot@iot.bzh> - * - * 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. - */ diff --git a/signal-composer-binding/signal-conf.hpp b/signal-composer-binding/signal-conf.hpp deleted file mode 100644 index 3698135..0000000 --- a/signal-composer-binding/signal-conf.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2015, 2016 "IoT.bzh" - * Author "Romain Forlot" <romain.forlot@iot.bzh> - * - * 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. - */ - -#include <json.hpp> - - class signalConfiguration -{ -private: - nlohmann::json config_; - -public: - void parseConfig(std::string configPath); -} diff --git a/signal-composer-binding/signal.cpp b/signal-composer-binding/signal.cpp index 6b4947e..0689a99 100644 --- a/signal-composer-binding/signal.cpp +++ b/signal-composer-binding/signal.cpp @@ -15,72 +15,111 @@ * limitations under the License. */ -#include "signal.hpp" +#include <memory> -Signal::Signal() -{} +#include "signal.hpp" +#include "signal-composer.hpp" -Signal(std::string& id, - std::vector<std::string>& sources, - std::string& unit, - float frequency, - CtlActionT* onReceived) +Signal::Signal(const std::string& id, + std::vector<std::string>& sources, + const std::string& unit, + double frequency, + CtlActionT* onReceived) :id_(id), - sources_(sources), - unit_(unit), + sourcesSig_(sources), frequency_(frequency), + unit_(unit), onReceived_(onReceived) +{} + +Signal::operator bool() const +{ + if(id_.empty()) + {return false;} + return true; +} + +bool Signal::operator ==(const Signal& other) const { - for (const std::string& src: sources) + if(id_ == other.id_) {return true;} + return false; +} + +bool Signal::operator==(const std::string& aName) const +{ + if(id_ == aName) {return true;} + for( const std::string& src : sourcesSig_) { - if(src.find("/") == std::string::npos) + if(src == aName) {return true;} + } + return false; +} + +std::string Signal::id() const +{ + return id_; +} +void update(double timestamp, double value) +{ + AFB_NOTICE("Got an update from observed signal"); +} + +int Signal::onReceivedCB(json_object *queryJ) +{ + return ActionExecOne(onReceived_, queryJ); +} + +void Signal::attach(Signal* obs) +{ + Observers_.push_back(obs); +} + +void Signal::attachToSources(bindingApp& bApp) +{ + for (const std::string& srcSig: sourcesSig_) + { + if(srcSig.find("/") == std::string::npos) { - AFB_NOTICE("Attaching %s to %s", sig->id(), src); - if(sig.attach(src)) - {AFB_WARNING("Can't attach. Is %s exists ?", src);} + std::shared_ptr<Signal> sig = bApp.searchSignal(srcSig); + if(sig) + { + AFB_NOTICE("Attaching %s to %s", id_.c_str(), srcSig.c_str()); + sig->attach(this); + continue; + } + AFB_WARNING("Can't attach. Is %s exists ?", srcSig.c_str()); } } } -Signal::operator bool() const +void Signal::notify() { - if(!id_ || !api_ || !signalName_) - {return false;} - return true; + for (int i = 0; i < Observers_.size(); ++i) + Observers_[i]->update(timestamp_, value_); } int Signal::recursionCheck(const std::string& origId) { for (const auto& obs: Observers_) { - if( id_ == obs.id()) + if( id_ == obs->id()) {return -1;} - if( origId == obs.id()) + if( origId == obs->id()) {return -1;} - if(! obs.recursionCheck(origId)) + if(! obs->recursionCheck(origId)) {return -1;} } return 0; } -std::string Signal::id() const -{ - return id_; -} - int Signal::recursionCheck() { for (const auto& obs: Observers_) { - if( id_ == obs.id()) + if( id_ == obs->id()) {return -1;} - if(! obs.recursionCheck(id_)) + if( obs->recursionCheck(id_)) {return -1;} } return 0; } - -void update(double timestamp, double value) -{ - AFB_NOTICE("Got an update from observed signal"); -} diff --git a/signal-composer-binding/signal.hpp b/signal-composer-binding/signal.hpp index ad944aa..cb50c67 100644 --- a/signal-composer-binding/signal.hpp +++ b/signal-composer-binding/signal.hpp @@ -19,40 +19,43 @@ #include <map> #include <string> -#include <memory> #include <vector> #include <ctl-config.h> -#include "observer.hpp" +class bindingApp; -class Signal; - -//TODO: claneys: define observer and observable interface then inherit -class Signal: public Observer, public Subject +class Signal { private: std::string id_; - std::vector<std::string> sources_; - std::map<long, double> history_; ///< history_ - Hold signal value history in map with <timestamp, value> + std::vector<std::string> sourcesSig_; + long long int timestamp_; + double value_; + std::map<long long int, double> history_; ///< history_ - Hold signal value history in map with <timestamp, value> double frequency_; std::string unit_; CtlActionT* onReceived_; + std::vector<Signal*> Observers_; - std::vector<std::shared_ptr<Signal>> observers_; - + void attach(Signal *obs); int recursionCheck(const std::string& origId); + public: - Signal(); Signal(const std::string& id, std::vector<std::string>& sources, 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; std::string id() const; - int recursionCheck(); - /* virtual */ void update(double timestamp, double value); + void update(long long int timestamp, double value); + int onReceivedCB(json_object *queryJ); + void attachToSources(bindingApp& bApp); + void notify(); - virtual double average() const; - virtual double min() const; - virtual double max() const; - double lastValue() const; + //virtual double average() const; + //virtual double min() const; + //virtual double max() const; + //double lastValue() const; + int recursionCheck(); }; diff --git a/signal-composer-binding/source.cpp b/signal-composer-binding/source.cpp index 919ae5b..6e7fec2 100644 --- a/signal-composer-binding/source.cpp +++ b/signal-composer-binding/source.cpp @@ -17,26 +17,35 @@ #include "source.hpp" -Source::Source() +SourceAPI::SourceAPI() {} -Source::Source(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal): +SourceAPI::SourceAPI(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal): api_(api), info_(info), init_(init), getSignal_(getSignal) {} -std::string Source::api() +std::string SourceAPI::api() const { return api_; } -void Source::addSignal(const std::string& id, std::vector<std::string>& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived) +void SourceAPI::addSignal(const std::string& id, std::vector<std::string>& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived) { std::shared_ptr<Signal> sig = std::make_shared<Signal>(id, sources, unit, frequency, onReceived); signals_.push_back(sig); } -std::vector<std::shared_ptr<Signal>> Source::getSignals() +std::vector<std::shared_ptr<Signal>> SourceAPI::getSignals() const { return signals_; } + +std::shared_ptr<Signal> SourceAPI::searchSignal(const std::string& name) const +{ + for (auto& sig: signals_) + { + if(*sig == name) {return sig;} + } + return nullptr; +} diff --git a/signal-composer-binding/source.hpp b/signal-composer-binding/source.hpp index 694daae..c1644c5 100644 --- a/signal-composer-binding/source.hpp +++ b/signal-composer-binding/source.hpp @@ -18,12 +18,10 @@ #pragma once #include <memory> -#include <ctl-config.h> -#include <signal-composer-binding.hpp> #include "signal.hpp" -class Source { +class SourceAPI { private: std::string api_; std::string info_; @@ -33,10 +31,12 @@ private: std::vector<std::shared_ptr<Signal>> signals_; public: - Source(); - Source(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal); + SourceAPI(); + SourceAPI(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal); - std::string api(); + std::string api() const; void addSignal(const std::string& id, std::vector<std::string>& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived); - std::vector<std::shared_ptr<Signal>> getSignals(); + + std::vector<std::shared_ptr<Signal>> getSignals() const; + std::shared_ptr<Signal> searchSignal(const std::string& name) const; }; |