summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--conf.d/project/etc/sig-demoboard.json16
-rw-r--r--conf.d/project/etc/sig-doors.json65
-rw-r--r--conf.d/project/etc/sig-geoloc.json105
-rw-r--r--conf.d/project/etc/sources.json25
-rw-r--r--plugins/low-can.cpp51
-rw-r--r--signal-composer-binding/signal-composer-binding.cpp20
-rw-r--r--signal-composer-binding/signal-composer.cpp184
-rw-r--r--signal-composer-binding/signal-composer.hpp11
-rw-r--r--signal-composer-binding/signal.cpp64
-rw-r--r--signal-composer-binding/signal.hpp8
-rw-r--r--signal-composer-binding/source.cpp42
-rw-r--r--signal-composer-binding/source.hpp8
12 files changed, 368 insertions, 231 deletions
diff --git a/conf.d/project/etc/sig-demoboard.json b/conf.d/project/etc/sig-demoboard.json
index c078d27..3d03f3e 100644
--- a/conf.d/project/etc/sig-demoboard.json
+++ b/conf.d/project/etc/sig-demoboard.json
@@ -1,11 +1,12 @@
{
"signals": [
{
- "label": "low-can/messages.vehicle.speed",
+ "id": "vehicle_speed",
+ "event": "low-can/messages.vehicle.speed",
"class": "temporal",
"unit": "km/h",
"frequency": 1,
- "actions": {
+ "onReceived": {
"label": "Unit converter",
"lua": "_Unit_Converter",
"args": {
@@ -15,22 +16,25 @@
}
},
{
- "name": "low-can/diagnostic_messages.engine.speed",
+ "id": "engine_speed",
+ "event": "low-can/diagnostic_messages.engine.speed",
"class": "temporal",
"unit": "rpm",
"frequency": 1
},
{
- "name": "low-can/diagnostic_messages.fuel.level",
+ "id": "fuel_level",
+ "event": "low-can/diagnostic_messages.fuel.level",
"class":"temporal",
"unit": "litre",
"frequency": 1
},
{
- "name": "low-can/diagnostic_messages.engine.load",
+ "id": "engine_load",
+ "event": "low-can/diagnostic_messages.engine.load",
"class":"temporal",
"unit": "Nm",
- "interval": 1
+ "frequency": 1
}
]
}
diff --git a/conf.d/project/etc/sig-doors.json b/conf.d/project/etc/sig-doors.json
index ea191e4..1d23f9a 100644
--- a/conf.d/project/etc/sig-doors.json
+++ b/conf.d/project/etc/sig-doors.json
@@ -2,10 +2,9 @@
"signals": [
{
"id": "rear_left_window",
- "source": "low-can/messages.windows.rear_left.open",
+ "event": "low-can/messages.windows.rear_left.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -13,10 +12,9 @@
},
{
"id": "rear_left_door",
- "source": "low-can/messages.doors.rear_left.open",
+ "event": "low-can/messages.doors.rear_left.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -24,10 +22,9 @@
},
{
"id": "rear_right_window",
- "source": "low-can/messages.windows.rear_right.open",
+ "event": "low-can/messages.windows.rear_right.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -35,10 +32,9 @@
},
{
"id": "rear_right_door",
- "source": "low-can/messages.doors.rear_right.open",
+ "event": "low-can/messages.doors.rear_right.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -46,10 +42,9 @@
},
{
"id": "front_left_window",
- "source": "low-can/messages.windows.front_left.open",
+ "event": "low-can/messages.windows.front_left.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -57,10 +52,9 @@
},
{
"id": "front_left_door",
- "source": "low-can/messages.doors.front_left.open",
+ "event": "low-can/messages.doors.front_left.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -68,10 +62,9 @@
},
{
"id": "front_right_window",
- "source": "low-can/messages.windows.front_right.open",
+ "event": "low-can/messages.windows.front_right.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -79,10 +72,9 @@
},
{
"id": "front_right_door",
- "source": "low-can/messages.doors.front_right.open",
+ "event": "low-can/messages.doors.front_right.open",
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -90,13 +82,12 @@
},
{
"id": "rear_left",
- "source": [
+ "depends": [
"rear_left_window",
"rear_left_door"
],
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"ojoi": "pok"
}
@@ -104,43 +95,40 @@
},
{
"id": "rear_right",
- "source": [
+ "depends": [
"rear_right_door",
"rear_right_window"
],
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {}
}
},
{
"id": "front_left",
- "source": [
+ "depends": [
"front_left_door",
"front_left_window"
],
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {}
}
},
{
"id": "front_right",
- "source": [
+ "depends": [
"front_right_door",
"front_right_window"
],
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {}
}
},
{
"id": "all_doors",
- "source": [
+ "depends": [
"front_left_door",
"front_left_window",
"front_right_door",
@@ -151,8 +139,7 @@
"rear_right_window"
],
"onReceived": {
- "plugin": "low-can-callbacks",
- "function": "isOpen",
+ "function": "plugin://low-can-callbacks/isOpen",
"args": {
"evtname": "doors.open"
}
diff --git a/conf.d/project/etc/sig-geoloc.json b/conf.d/project/etc/sig-geoloc.json
index 7fc4d29..3b0e4eb 100644
--- a/conf.d/project/etc/sig-geoloc.json
+++ b/conf.d/project/etc/sig-geoloc.json
@@ -1,136 +1,155 @@
{
"signals": [
{
- "label": "gps/latitude",
- "class": "state",
+ "id": "latitude",
+ "event": "gps/location",
"unit": "degree",
- "frequency": 1
+ "frequency": 1,
+ "onReceived": {
+ "function": "plugin://gps-callbacks/getLatitude"
+ }
},
{
- "label": "gps/longitude",
- "class": "state",
+ "id": "longitude",
+ "event": "gps/location",
"unit": "degree",
- "frequency": 1
+ "frequency": 1,
+ "onReceived": {
+ "function": "plugin://gps-callbacks/getSignal",
+ "args": {
+ "what": "longitude"
+ }
+ }
},
{
- "label": "gps/altitude",
- "class": "state",
+ "id": "altitude",
+ "event": "gps/location",
"unit": "meter",
"frequency": 1
},
{
- "label": "heading",
+ "id": "heading",
+ "depends": [
+ "latitude",
+ "longitude"
+ ],
"class": "state",
"unit": "degree",
"frequency": 1,
- "dependsOn": [
- "gps/latitude",
- "gps/longitude"
- ],
"actions": {
- "label": "Heading calculation",
+ "id": "Heading calculation",
"lua": "_Heading",
"args": {}
}
},
{
- "label": "gps/speed",
+ "id": "speed",
+ "event": "gps/location",
"class": "temporal",
"unit": "m/s",
"frequency": 1
},
{
- "label": "mraa/climb",
- "class": "state",
+ "id": "climb",
+ "event": "mraa/getclimb",
"unit": "degree",
"frequency": 1
},
{
- "label": "mraa/roll_rate",
- "class": "state",
+ "id": "roll_rate",
+ "event": "mraa/gyroscope",
"unit": "degree/s",
"frequency": 1
},
{
- "label": "mraa/roll_rate",
- "class": "state",
+ "id": "pitch_rate",
+ "event": "mraa/gyroscope",
"unit": "degree/s",
"frequency": 1
},
{
- "label": "mraa/roll_rate",
- "class": "state",
+ "id": "yaw_rate",
+ "event": "gps/gyroscope",
"unit": "degree/s",
"frequency": 1
},
{
- "label": "gps/pdop",
+ "id": "pdop",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/hdop",
+ "id": "hdop",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/vdop",
+ "id": "vdop",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/used_satellites",
+ "id": "used_satellites",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/tracked_satellites",
+ "id": "tracked_satellites",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/visible_satellites",
+ "id": "visible_satellites",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/sigma_hposition",
- "class": "state",
+ "id": "sigma_hposition",
+ "event": "gps/location",
"unit": "meter",
"frequency": 1
},
{
- "label": "gps/sigma_altitude",
- "class": "state",
+ "id": "sigma_altitude",
+ "event": "gps/location",
"unit": "meter",
"frequency": 1
},
{
- "label": "gps/sigma_heading",
- "class": "state",
+ "id": "sigma_heading",
+ "event": "gps/location",
"unit": "degree",
"frequency": 1
},
{
- "label": "gps/sigma_speed",
+ "id": "sigma_speed",
+ "event": "gps/location",
"class": "temporal",
"unit": "m/s",
"frequency": 1
},
{
- "label": "gps/sigma_climb",
- "class": "state",
+ "id": "sigma_climb",
+ "event": "gps/location",
"unit": "degree",
"frequency": 1
},
{
- "label": "gps/gnss_fix_status",
- "class": "state",
+ "id": "gnss_fix_status",
+ "event": "gps/location",
"frequency": 1
},
{
- "label": "gps/dr_status",
+ "id": "dr_status",
+ "event": "gps/location",
"class": "state",
"frequency": 1
},
{
- "label": "gps/reliabilty_index",
+ "id": "reliabilty_index",
+ "event": "gps/location",
"class": "temporal",
"frequency": 1
}
]
-} \ No newline at end of file
+}
diff --git a/conf.d/project/etc/sources.json b/conf.d/project/etc/sources.json
index 6a9657a..be99a41 100644
--- a/conf.d/project/etc/sources.json
+++ b/conf.d/project/etc/sources.json
@@ -4,14 +4,13 @@
"api": "low-can",
"info": "Low level binding to handle CAN bus communications",
"init": {
- "function": "low-can/subscribe",
+ "function": "api://low-can/subscribe",
"args": {
"event": "message*"
}
- },
- "getSignal": {
- "plugin": "low-can-callbacks",
- "function": "subscribeToLow",
+ },
+ "getSignals": {
+ "function": "plugin://low-can-callbacks/subscribeToLow",
"args": {
"arg": "first argument"
}
@@ -20,13 +19,13 @@
"api": "gps",
"info": "Low level binding which retrieve Satellite positionning values",
"init": {
- "function": "_LUA_Simple_Echo_Args",
+ "function": "api://gps/location",
"args": {
"arg1": "first argument"
}
- },
- "getSignal": {
- "function": "_LUA_Simple_Echo_Args",
+ },
+ "getSignals": {
+ "function": "lua://_Simple_Echo_Args",
"args": {
"arg": "first argument"
}
@@ -35,13 +34,13 @@
"api": "mraa",
"info": "Low level binding which retrieve different values from several sensors like gyroscope, accelerometer, etc",
"init": {
- "function": "_LUA_Simple_Echo_Args",
+ "function": "lua://_Simple_Echo_Args",
"args": {
"arg1": "first argument"
}
- },
- "getSignal": {
- "function": "_LUA_Simple_Echo_Args",
+ },
+ "getSignals": {
+ "function": "lua://_Simple_Echo_Args",
"args": {
"arg": "first argument"
}
diff --git a/plugins/low-can.cpp b/plugins/low-can.cpp
index 1f528a5..8b573ba 100644
--- a/plugins/low-can.cpp
+++ b/plugins/low-can.cpp
@@ -77,15 +77,18 @@ CTLP_ONLOAD(plugin, bAppHandle)
}
CTLP_CAPI (subscribeToLow, source, argsJ, eventJ, context) {
- json_object* signalArrayJ = NULL, *subscribeArgsJ = NULL, *subscribeFilterJ = NULL, *responseJ = NULL;
- const char* unit = NULL;
+ json_object* dependsArrayJ = nullptr, *subscribeArgsJ = nullptr, *subscribeFilterJ = nullptr, *responseJ = nullptr, *filterJ = nullptr;
+ const char *id = nullptr, *event = nullptr, *unit = nullptr;
double frequency = 0;
int err = 0;
- err = wrap_json_unpack(eventJ, "{so,s?s,s?F !}",
- "signal", &signalArrayJ,
+ err = wrap_json_unpack(eventJ, "{ss,s?s,s?o,s?s,s?F,s?o !}",
+ "id", &id,
+ "event", &event,
+ "depends", &dependsArrayJ,
"unit", &unit,
- "frequency", &frequency);
+ "frequency", &frequency,
+ "getSignalsArgs", &filterJ);
if(err)
{
AFB_ERROR("Problem to unpack JSON object eventJ: %s",
@@ -93,29 +96,27 @@ CTLP_CAPI (subscribeToLow, source, argsJ, eventJ, context) {
return err;
}
- if(frequency > 0)
+ if(frequency > 0 && !filterJ)
+ {wrap_json_pack(&subscribeFilterJ, "{sf}", "frequency", frequency);}
+ else
+ {subscribeFilterJ = filterJ;}
+
+ std::string eventStr = std::string(event);
+ std::string lowEvent = eventStr.substr(eventStr.find("/")+1);
+ err = wrap_json_pack(&subscribeArgsJ, "{ss, so*}",
+ "event", lowEvent.c_str(),
+ "filter", subscribeFilterJ);
+ if(err)
{
- wrap_json_pack(&subscribeFilterJ, "{sf}", "frequency", frequency);
+ AFB_ERROR("Error building subscription query object");
+ return err;
}
-
- for (int idx = 0; idx < json_object_array_length(signalArrayJ); idx++)
+ 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)
{
- 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;
- }
+ AFB_ERROR("Can't find api 'low-can'");
+ return err;
}
return err;
diff --git a/signal-composer-binding/signal-composer-binding.cpp b/signal-composer-binding/signal-composer-binding.cpp
index c70941a..4f12150 100644
--- a/signal-composer-binding/signal-composer-binding.cpp
+++ b/signal-composer-binding/signal-composer-binding.cpp
@@ -39,6 +39,7 @@ void onEvent(const char *event, json_object *object)
sig->onReceivedCB(object);
}
}
+
/// @brief entry point for client subscription request.
void subscribe(afb_req request)
{
@@ -60,14 +61,19 @@ void unsubscribe(afb_req request)
/// @brief verb that loads JSON configuration (old SigComp.json file now)
void loadConf(afb_req request)
{
- json_object* args = afb_req_json(request);
- const char* confd;
+ json_object* args = afb_req_json(request), *fileJ;
+ const char* filepath;
- wrap_json_unpack(args, "{s:s}", "path", &confd);
- if(true)
- afb_req_success(request, NULL, NULL);
+ wrap_json_unpack(args, "{s:s}", "filepath", &filepath);
+ fileJ = json_object_from_file(filepath);
+
+ if(bindingApp::instance().loadSignals(fileJ))
+ {afb_req_fail_f(request, "Loading configuration or subscription error", "Error code: -1");}
else
- afb_req_fail_f(request, "Loading configuration or subscription error", "Error code: -1");
+ {
+
+ afb_req_success(request, NULL, NULL);
+ }
}
/// @brief entry point to list available signals
@@ -79,7 +85,7 @@ void list(afb_req request)
for(auto& sig: allSignals)
{json_object_array_add(allSignalsJ, sig->toJSON());}
- if(json_object_array_length(allSignalsJ))
+ if(json_object_array_length(allSignalsJ) && !execConf())
{
afb_req_success(request, allSignalsJ, NULL);
}
diff --git a/signal-composer-binding/signal-composer.cpp b/signal-composer-binding/signal-composer.cpp
index b29df22..151de6c 100644
--- a/signal-composer-binding/signal-composer.cpp
+++ b/signal-composer-binding/signal-composer.cpp
@@ -16,6 +16,7 @@
*/
#include <string.h>
+#include <fnmatch.h>
#include "signal-composer.hpp"
@@ -26,15 +27,23 @@ extern "C" void setSignalValueHandle(const char* aName, long long int timestamp,
{sig->set(timestamp, value);}
}
+bool startsWith(const std::string& str, const std::string& pattern)
+{
+ size_t sep;
+ if( (sep = str.find(pattern)) != std::string::npos && !sep)
+ {return true;}
+ return false;
+}
+
static struct pluginCBT pluginHandle = {
.setSignalValue = setSignalValueHandle,
};
CtlSectionT bindingApp::ctlSections_[] = {
- [0]={.key="plugins" ,.label = "plugins", .info=nullptr,
+ [0]={.key="plugins" , .label = "plugins", .info=nullptr,
.loadCB=PluginConfig,
.handle=&pluginHandle},
- [1]={.key="sources" ,.label = "sources", .info=nullptr,
+ [1]={.key="sources" , .label = "sources", .info=nullptr,
.loadCB=loadSourcesAPI,
.handle=nullptr},
[2]={.key="signals" , .label= "signals", .info=nullptr,
@@ -68,7 +77,7 @@ bindingApp& bindingApp::instance()
SourceAPI* bindingApp::getSourceAPI(const std::string& api)
{
- for(auto& source: sourcesList_)
+ for(auto& source: sourcesListV_)
{
if (source.api() == api)
{return &source;}
@@ -76,6 +85,27 @@ SourceAPI* bindingApp::getSourceAPI(const std::string& api)
return nullptr;
}
+std::vector<std::string> bindingApp::parseURI(const std::string& uri)
+{
+ std::vector<std::string> uriV;
+ std::string delimiters = "/";
+
+ std::string::size_type start = 0;
+ auto pos = uri.find_first_of(delimiters, start);
+ while(pos != std::string::npos)
+ {
+ if(pos != start) // ignore empty tokens
+ uriV.emplace_back(uri, start, pos - start);
+ start = pos + 1;
+ pos = uri.find_first_of(delimiters, start);
+ }
+
+ if(start < uri.length()) // ignore trailing delimiter
+ uriV.emplace_back(uri, start, uri.length() - start); // add what's left of the string
+
+ return uriV;
+}
+
CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* actionJ)
{
json_object *functionArgsJ = nullptr, *action = nullptr;
@@ -88,35 +118,52 @@ CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* act
"args", &functionArgsJ))
{
action = nullptr;
- if(::strcasestr(function, "lua"))
+ if(startsWith(function, "lua://"))
{
+ std::string fName = std::string(function).substr(6);
wrap_json_pack(&action, "{ss,ss,so*}",
"label", name.c_str(),
- "lua", function,
+ "lua", fName,
"args", functionArgsJ);
}
- else if(strstr(function, "/"))
+ else if(startsWith(function, "api://"))
{
- const char* api = strsep(&function, "/");
- //std::string api = functionS.substr(0, sep);
- //std::string verb = functionS.substr(sep);
+ std::string uri = std::string(function).substr(6);
+ std::vector<std::string> uriV = bindingApp::parseURI(uri);
+ if(uriV.size() != 2)
+ {
+ AFB_ERROR("Miss something in uri either plugin name or function name. Uri has to be like: api://<plugin-name>/<function-name>");
+ return nullptr;
+ }
wrap_json_pack(&action, "{ss,ss,ss,so*}",
"label", name.c_str(),
- "api", api,
- "verb", function,
+ "api", uriV[0].c_str(),
+ "verb", uriV[1].c_str(),
"args", functionArgsJ);
}
- else
+ else if(startsWith(function, "plugin://"))
{
+ std::string uri = std::string(function).substr(9);
+ std::vector<std::string> uriV = bindingApp::parseURI(uri);
+ if(uriV.size() != 2)
+ {
+ AFB_ERROR("Miss something in uri either plugin name or function name. Uri has to be like: plugin://<plugin-name>/<function-name>");
+ return nullptr;
+ }
json_object *callbackJ = nullptr;
wrap_json_pack(&callbackJ, "{ss,ss,so*}",
- "plugin", plugin,
- "function", function,
+ "plugin", uriV[0].c_str(),
+ "function", uriV[1].c_str(),
"args", functionArgsJ);
wrap_json_pack(&action, "{ss,so}",
"label", name.c_str(),
"callback", callbackJ);
}
+ else
+ {
+ AFB_ERROR("Wrong function uri specified. You have to specified 'lua://', 'plugin://' or 'api://'. (%s)", function);
+ return nullptr;
+ }
}
if(action) {return ActionLoad(action);}
return nullptr;
@@ -124,18 +171,18 @@ CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* act
int bindingApp::loadOneSourceAPI(json_object* sourceJ)
{
- json_object *initJ = nullptr, *getSignalJ = nullptr;
- CtlActionT *initCtl = nullptr, *getSignalCtl = nullptr;
+ json_object *initJ = nullptr, *getSignalsJ = nullptr;
+ CtlActionT *initCtl = nullptr, *getSignalsCtl = nullptr;
const char *api, *info;
int err = wrap_json_unpack(sourceJ, "{ss,s?s,s?o,s?o !}",
"api", &api,
"info", &info,
"init", &initJ,
- "getSignal", &getSignalJ);
+ "getSignals", &getSignalsJ);
if (err)
{
- AFB_ERROR("Missing something api|[info]|[init]|[getSignal] in %s", json_object_get_string(sourceJ));
+ AFB_ERROR("Missing something api|[info]|[init]|[getSignals] in %s", json_object_get_string(sourceJ));
return err;
}
@@ -147,9 +194,9 @@ int bindingApp::loadOneSourceAPI(json_object* sourceJ)
}
if(initJ) {initCtl = convert2Action("init", initJ);}
- if(getSignalJ) {getSignalCtl = convert2Action("getSignal", getSignalJ);}
+ if(getSignalsJ) {getSignalsCtl = convert2Action("getSignals", getSignalsJ);}
- sourcesList_.push_back(SourceAPI(api, info, initCtl, getSignalCtl));
+ sourcesListV_.push_back(SourceAPI(api, info, initCtl, getSignalsCtl));
return err;
}
@@ -192,64 +239,96 @@ int bindingApp::loadSourcesAPI(CtlSectionT* section, json_object *sourcesJ)
int bindingApp::loadOneSignal(json_object* signalJ)
{
- json_object *onReceivedJ = nullptr, *sourcesJ = nullptr;
+ json_object *onReceivedJ = nullptr, *dependsJ = nullptr, *getSignalsArgs = nullptr;
CtlActionT* onReceivedCtl;
const char *id = nullptr,
+ *event = nullptr,
*sClass = nullptr,
*unit = nullptr;
- double frequency;
+ double frequency=0.0;
std::string api;
- std::vector<std::string> sourcesV;
+ std::vector<std::string> dependsV;
ssize_t sep;
- int err = wrap_json_unpack(signalJ, "{ss,so,s?s,s?s,s?F,s?o !}",
+ int err = wrap_json_unpack(signalJ, "{ss,s?s,s?o,s?o,s?s,s?s,s?F,s?o !}",
"id", &id,
- "source", &sourcesJ,
+ "event", &event,
+ "depends", &dependsJ,
+ "getSignalsArgs", &getSignalsArgs,
"class", &sClass,
"unit", &unit,
"frequency", &frequency,
"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|[event|depends]|[getSignalsArgs]|[class]|[unit]|[frequency]|[onReceived] in %s", json_object_get_string(signalJ));
return err;
}
- // Process sources JSON object
- if (json_object_get_type(sourcesJ) == json_type_array)
+ // Set default sClass is not specified
+ sClass = !sClass ? "state" : sClass;
+ unit = !unit ? "" : unit;
+
+ // Get an action handler
+ onReceivedCtl = onReceivedJ ? convert2Action("onReceived", onReceivedJ) : nullptr;
+
+ // event or depends field manadatory
+ if( (!event && !dependsJ) || (event && dependsJ) )
+ {
+ AFB_ERROR("Missing something id|[event|depends]|[getSignalsArgs]|[class]|[unit]|[frequency]|[onReceived] in %s. Or you declare event AND depends, only one of them is needed.", json_object_get_string(signalJ));
+ return -1;
+ }
+
+ // Process depends JSON object to declare virtual signal dependencies
+ if (dependsJ)
{
- int count = json_object_array_length(sourcesJ);
- for(int i = 0; i < count; i++)
+ if(json_object_get_type(dependsJ) == json_type_array)
+ {
+ int count = json_object_array_length(dependsJ);
+ for(int i = 0; i < count; i++)
+ {
+ std::string sourceStr = json_object_get_string(json_object_array_get_idx(dependsJ, 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");
+ return -1;
+ }
+ dependsV.push_back(sourceStr);
+ }
+ api = sourcesListV_.rbegin()->api();
+ }
+ else
{
- std::string sourceStr = json_object_get_string(json_object_array_get_idx(sourcesJ, i));
+ std::string sourceStr = json_object_get_string(dependsJ);
if( (sep = sourceStr.find("/")) != std::string::npos)
{
AFB_ERROR("Signal composition needs to use signal 'id', don't use full low level signal name");
return -1;
}
- sourcesV.push_back(sourceStr);
+ dependsV.push_back(sourceStr);
+ api = sourcesListV_.rbegin()->api();
}
}
- else
+
+ // Declare a raw signal
+ if(event)
{
- std::string sourceStr = json_object_get_string(sourcesJ);
- if( (sep = sourceStr.find("/")) != std::string::npos)
+ std::string eventStr = std::string(event);
+ if( (sep = eventStr.find("/")) == std::string::npos)
{
- api = sourceStr.substr(0, sep);
+ AFB_ERROR("Missing something in event declaration. Has to be like: <api>/<event>");
+ return -1;
}
- sourcesV.push_back(sourceStr);
+ api = eventStr.substr(0, sep);
+ }
+ else
+ {
+ event = "";
}
-
- // Set default sClass is not specified
- sClass = !sClass ? "state" : sClass;
- unit = !unit ? "" : unit;
-
- // Get an action handler
- onReceivedCtl = convert2Action("onReceived", onReceivedJ);
SourceAPI* src = getSourceAPI(api) ? getSourceAPI(api):getSourceAPI("signal-composer");
- if( src != nullptr)
- {src->addSignal(id, sourcesV, sClass, unit, frequency, onReceivedCtl);}
+ if(src != nullptr)
+ {src->addSignal(id, event, dependsV, sClass, unit, frequency, onReceivedCtl, getSignalsArgs);}
else
{err = -1;}
@@ -281,6 +360,11 @@ int bindingApp::loadSignals(CtlSectionT* section, json_object *signalsJ)
return err;
}
+int bindingApp::loadSignals(json_object* signalsJ)
+{
+ return loadSignals(nullptr, signalsJ);
+}
+
std::shared_ptr<Signal> bindingApp::searchSignal(const std::string& aName)
{
std::string api;
@@ -306,7 +390,7 @@ std::shared_ptr<Signal> bindingApp::searchSignal(const std::string& aName)
std::vector<std::shared_ptr<Signal>> bindingApp::getAllSignals()
{
std::vector<std::shared_ptr<Signal>> allSignals;
- for( auto& source : sourcesList_)
+ for( auto& source : sourcesListV_)
{
std::vector<std::shared_ptr<Signal>> srcSignals = source.getSignals();
allSignals.insert(allSignals.end(), srcSignals.begin(), srcSignals.end());
@@ -320,14 +404,14 @@ CtlConfigT* bindingApp::ctlConfig()
return ctlConfig_;
}
-int bindingApp::execSubscription() const
+int bindingApp::execSubscription()
{
int err = 0;
- for(const SourceAPI& srcAPI: sourcesList_)
+ for(SourceAPI& srcAPI: sourcesListV_)
{
if (srcAPI.api() != std::string(ctlConfig_->api))
{
- err += srcAPI.makeSubscription();
+ err = srcAPI.makeSubscription();
}
}
return err;
diff --git a/signal-composer-binding/signal-composer.hpp b/signal-composer-binding/signal-composer.hpp
index 341eaab..4050700 100644
--- a/signal-composer-binding/signal-composer.hpp
+++ b/signal-composer-binding/signal-composer.hpp
@@ -28,7 +28,7 @@ private:
CtlConfigT* ctlConfig_;
static CtlSectionT ctlSections_[]; ///< Config Section definition (note: controls section index should match handle retrieval in)
- std::vector<SourceAPI> sourcesList_;
+ std::vector<SourceAPI> sourcesListV_;
explicit bindingApp(const std::string& filepath);
bindingApp();
@@ -37,15 +37,16 @@ private:
CtlActionT* convert2Action(const std::string& name, json_object* action);
int loadOneSourceAPI(json_object* sourcesJ);
- static int loadSourcesAPI(CtlSectionT* section, json_object *sectionJ);
+ static int loadSourcesAPI(CtlSectionT* section, json_object *signalsJ);
int loadOneSignal(json_object* signalsJ);
- static int loadSignals(CtlSectionT* section, json_object *sectionJ);
+ static int loadSignals(CtlSectionT* section, json_object *signalsJ);
public:
static bindingApp& instance();
+ static std::vector<std::string> parseURI(const std::string& uri);
int loadConfig(const std::string& filepath);
- //void loadSignalsFile(std::string signalsFile);
+ int loadSignals(json_object* signalsJ);
CtlConfigT* ctlConfig();
std::vector<std::shared_ptr<Signal>> getAllSignals();
@@ -53,7 +54,7 @@ public:
std::shared_ptr<Signal> searchSignal(const std::string& aName);
json_object* getSignalValue(const std::string& sig, json_object* options);
- int execSubscription() const;
+ int execSubscription();
};
struct pluginCBT
diff --git a/signal-composer-binding/signal.cpp b/signal-composer-binding/signal.cpp
index ea5a324..1679a6f 100644
--- a/signal-composer-binding/signal.cpp
+++ b/signal-composer-binding/signal.cpp
@@ -24,18 +24,32 @@
#define MICRO 1000000
+Signal::Signal(const std::string& id, const std::string& event, std::vector<std::string>& depends, const std::string& unit, double frequency, CtlActionT* onReceived, json_object* getSignalsArgs)
+:id_(id),
+ event_(event),
+ dependsSigV_(depends),
+ timestamp_(0.0),
+ value_({0,0,0,0,0,""}),
+ frequency_(frequency),
+ unit_(unit),
+ onReceived_(onReceived),
+ getSignalsArgs_(getSignalsArgs)
+{}
+
Signal::Signal(const std::string& id,
- std::vector<std::string>& sources,
- const std::string& unit,
- double frequency,
- CtlActionT* onReceived)
+ std::vector<std::string>& depends,
+ const std::string& unit,
+ double frequency,
+ CtlActionT* onReceived)
:id_(id),
- signalSigList_(sources),
+ event_(),
+ dependsSigV_(depends),
timestamp_(0.0),
value_({0,0,0,0,0,""}),
frequency_(frequency),
unit_(unit),
- onReceived_(onReceived)
+ onReceived_(onReceived),
+ getSignalsArgs_()
{}
Signal::operator bool() const
@@ -54,11 +68,8 @@ bool Signal::operator ==(const Signal& other) const
bool Signal::operator ==(const std::string& aName) const
{
if(! fnmatch(aName.c_str(), id_.c_str(), FNM_CASEFOLD)) {return true;}
- for( const std::string& src : signalSigList_)
- {
- if(! fnmatch(aName.c_str(), src.c_str(), FNM_CASEFOLD)) {return true;}
- if( src.find(aName) != std::string::npos) {return true;}
- }
+ if(event_.find(aName) != std::string::npos) {return true;}
+
return false;
}
@@ -70,24 +81,27 @@ const std::string Signal::id() const
json_object* Signal::toJSON() const
{
json_object* queryJ = nullptr;
- std::vector<std::string> lowSignalName;
- for (const std::string& src: signalSigList_ )
+ std::vector<std::string> dependsSignalName;
+ for (const std::string& src: dependsSigV_ )
{
ssize_t sep = src.find_first_of("/");
if(sep != std::string::npos)
{
- lowSignalName.push_back(src.substr(sep+1));
+ dependsSignalName.push_back(src.substr(sep+1));
}
}
json_object* nameArray = json_object_new_array();
- for (const std::string& lowSig: lowSignalName)
+ for (const std::string& lowSig: dependsSignalName)
{
json_object_array_add(nameArray, json_object_new_string(lowSig.c_str()));
}
- wrap_json_pack(&queryJ, "{so,ss*,sf*}",
- "signal", nameArray,
+ wrap_json_pack(&queryJ, "{ss,ss*,so*,ss*,sf*,so*}",
+ "id", id_.c_str(),
+ "event", event_.c_str(),
+ "depends", nameArray,
"unit", unit_.c_str(),
- "frequency", frequency_);
+ "frequency", frequency_,
+ "getSignalsArgs", getSignalsArgs_);
return queryJ;
}
@@ -104,6 +118,7 @@ void Signal::set(long long int timestamp, struct SignalValue& value)
{
timestamp_ = timestamp;
value_ = value;
+ history_[timestamp_] = value_;
}
/// @brief Observer method called when a Observable Signal has changes.
@@ -112,7 +127,7 @@ void Signal::set(long long int timestamp, struct SignalValue& value)
/// @param[in] value - value of change
void Signal::update(long long int timestamp, struct SignalValue value)
{
- AFB_NOTICE("Got an update from observed signal. Timestamp: %lld, vb: %d, vn: %lf, vs: %s", timestamp, value.boolVal, value.numVal, value.strVal.c_str());
+ AFB_DEBUG("Got an update from observed signal. Timestamp: %lld, vb: %d, vn: %lf, vs: %s", timestamp, value.boolVal, value.numVal, value.strVal.c_str());
}
/// @brief Notify observers that there is a change and execute callback defined
@@ -128,11 +143,18 @@ int Signal::onReceivedCB(json_object *queryJ)
return err;
}
-/// @brief Make a Signal observer observes a Signal observable
+/// @brief Make a Signal observer observes a Signal observable if not already
+/// present in the Observers vector.
///
/// @param[in] obs - pointer to a Signal observable
void Signal::attach(Signal* obs)
{
+ for ( auto& sig : Observers_)
+ {
+ if (obs == sig)
+ {return;}
+ }
+
Observers_.push_back(obs);
}
@@ -142,7 +164,7 @@ void Signal::attach(Signal* obs)
/// @param[in] bApp - bindinApp instance
void Signal::attachToSourceSignals(bindingApp& bApp)
{
- for (const std::string& srcSig: signalSigList_)
+ for (const std::string& srcSig: dependsSigV_)
{
if(srcSig.find("/") == std::string::npos)
{
diff --git a/signal-composer-binding/signal.hpp b/signal-composer-binding/signal.hpp
index 2088ffd..4e078fc 100644
--- a/signal-composer-binding/signal.hpp
+++ b/signal-composer-binding/signal.hpp
@@ -37,13 +37,16 @@ class Signal
{
private:
std::string id_;
- std::vector<std::string> signalSigList_;
+ std::string event_;
+ std::vector<std::string> dependsSigV_;
long long int timestamp_;
struct SignalValue value_;
std::map<long long int, struct SignalValue> history_; ///< history_ - Hold signal value history in map with <timestamp, value>
double frequency_;
std::string unit_;
CtlActionT* onReceived_;
+ json_object* getSignalsArgs_;
+
std::vector<Signal*> Observers_;
void notify();
@@ -51,7 +54,8 @@ private:
int recursionCheck(const std::string& origId);
public:
- Signal(const std::string& id, std::vector<std::string>& sources, const std::string& unit, double frequency, CtlActionT* onReceived);
+ Signal(const std::string& id, const std::string& event, std::vector<std::string>& depends, const std::string& unit, double frequency, CtlActionT* onReceived, json_object* getSignalsArgs);
+ Signal(const std::string& id, std::vector<std::string>& 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;
diff --git a/signal-composer-binding/source.cpp b/signal-composer-binding/source.cpp
index 80c59d6..1f5d588 100644
--- a/signal-composer-binding/source.cpp
+++ b/signal-composer-binding/source.cpp
@@ -20,8 +20,8 @@
SourceAPI::SourceAPI()
{}
-SourceAPI::SourceAPI(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal):
- api_(api), info_(info), init_(init), getSignal_(getSignal)
+SourceAPI::SourceAPI(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignals):
+ api_(api), info_(info), init_(init), getSignals_(getSignals)
{}
std::string SourceAPI::api() const
@@ -29,41 +29,51 @@ std::string SourceAPI::api() const
return api_;
}
-void SourceAPI::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, const std::string& event, std::vector<std::string>& depends, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived, json_object* getSignalsArgs)
{
- std::shared_ptr<Signal> sig = std::make_shared<Signal>(id, sources, unit, frequency, onReceived);
+ std::shared_ptr<Signal> sig = std::make_shared<Signal>(id, event, depends, unit, frequency, onReceived, getSignalsArgs);
- signalsList_.push_back(sig);
+ signalsMap_[sig] = false;
}
std::vector<std::shared_ptr<Signal>> SourceAPI::getSignals() const
{
- return signalsList_;
+ std::vector<std::shared_ptr<Signal>> signals;
+ for (auto& sig: signalsMap_)
+ {
+ signals.push_back(sig.first);
+ }
+ return signals;
}
std::shared_ptr<Signal> SourceAPI::searchSignal(const std::string& name) const
{
- for (auto& sig: signalsList_)
+ for (auto& sig: signalsMap_)
{
- if(*sig == name) {return sig;}
+ if(*sig.first == name) {return sig.first;}
}
return nullptr;
}
-int SourceAPI::makeSubscription() const
+int SourceAPI::makeSubscription()
{
int err = 0;
- if(getSignal_)
+ if(getSignals_)
{
- for(std::shared_ptr<Signal> sig: signalsList_)
+ for(auto& sig: signalsMap_)
{
- json_object* lowSignalNameJ = sig->toJSON();
- if(!lowSignalNameJ)
+ json_object* signalJ = sig.first->toJSON();
+ if(!signalJ)
{
- AFB_ERROR("Error building JSON query object to subscribe to for signal %s", sig->id().c_str());
- return -1;
+ AFB_ERROR("Error building JSON query object to subscribe to for signal %s", sig.first->id().c_str());
+ err = -1;
+ break;
}
- err += ActionExecOne(getSignal_, lowSignalNameJ);
+ err += sig.second ? 0:ActionExecOne(getSignals_, signalJ);
+ if(err)
+ {AFB_WARNING("Fails to subscribe to signal %s", sig.first->id().c_str());}
+ else
+ {sig.second = true;}
}
}
diff --git a/signal-composer-binding/source.hpp b/signal-composer-binding/source.hpp
index c295b6e..560a137 100644
--- a/signal-composer-binding/source.hpp
+++ b/signal-composer-binding/source.hpp
@@ -26,19 +26,19 @@ private:
std::string api_;
std::string info_;
CtlActionT* init_;
- CtlActionT* getSignal_;
+ CtlActionT* getSignals_;
- std::vector<std::shared_ptr<Signal>> signalsList_;
+ std::map<std::shared_ptr<Signal>, bool> signalsMap_;
public:
SourceAPI();
SourceAPI(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal);
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);
+ void addSignal(const std::string& id, const std::string& event, std::vector<std::string>& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived, json_object* getSignalsArgs);
std::vector<std::shared_ptr<Signal>> getSignals() const;
std::shared_ptr<Signal> searchSignal(const std::string& name) const;
- int makeSubscription() const;
+ int makeSubscription();
};