Skip to content
This repository was archived by the owner on Dec 18, 2024. It is now read-only.

Commit 9c41bb3

Browse files
Merge pull request #274 from boschresearch/feature/set_get_attributes
Get/Set Attribute
2 parents 883a74b + e2dbb6c commit 9c41bb3

26 files changed

+523
-218
lines changed

include/SubscriptionHandler.hpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,32 @@ struct UUIDHasher
5858
}
5959
};
6060
using subscriptions_t = std::unordered_map<SubscriptionId, SubConnId, UUIDHasher>;
61+
using subscription_keys_t = struct subscription_keys {
62+
std::string path;
63+
std::string attribute;
64+
65+
// constructor
66+
subscription_keys(std::string path, std::string attr) {
67+
this->path = path;
68+
this->attribute = attr;
69+
}
70+
71+
// Equal operator
72+
bool operator==(const subscription_keys &p) const {
73+
return this->path == p.path && this->attribute == p.attribute;
74+
}
75+
};
76+
77+
struct SubscriptionKeyHasher {
78+
std::size_t operator() (const subscription_keys_t& key) const {
79+
return (std::hash<VSSPath>()(VSSPath::fromVSS(key.path)) ^ std::hash<std::string>()(key.attribute));
80+
}
81+
};
6182

6283

6384
class SubscriptionHandler : public ISubscriptionHandler {
6485
private:
65-
std::unordered_map<VSSPath, subscriptions_t> subscriptions;
86+
std::unordered_map<subscription_keys_t, subscriptions_t, SubscriptionKeyHasher> subscriptions;
6687

6788
std::shared_ptr<ILogger> logger;
6889
std::shared_ptr<IServer> server;
@@ -88,10 +109,10 @@ class SubscriptionHandler : public ISubscriptionHandler {
88109
}
89110
SubscriptionId subscribe(kuksa::kuksaChannel& channel,
90111
std::shared_ptr<IVssDatabase> db,
91-
const std::string &path);
112+
const std::string &path, const std::string& attr);
92113
int unsubscribe(SubscriptionId subscribeID);
93114
int unsubscribeAll(ConnectionId connectionID);
94-
int publishForVSSPath(const VSSPath path, const jsoncons::json &value);
115+
int publishForVSSPath(const VSSPath path, const std::string& attr, const jsoncons::json &value);
95116

96117

97118
std::shared_ptr<IServer> getServer();

include/VSSPath.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class VSSPath {
3737
static VSSPath fromVSS(std::string vss); //Auto decide for Gen1 or Gen2
3838
inline bool operator==(const VSSPath& other) { return (vsspath == other.vsspath); };
3939

40-
inline bool operator< (const VSSPath& other){
40+
inline bool operator< (const VSSPath& other) {
4141
return vsspath < other.vsspath;
4242
}
4343

include/VSSRequestJsonSchema.hpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ static const char* SCHEMA_GET=R"(
3434
"enum": [ "get", "getMetaData" ],
3535
"description": "The identifier for the get request"
3636
},
37+
"attribute": {
38+
"enum": [ "targetValue", "value" ],
39+
"description": "The attributes to be fetched for the get request"
40+
},
3741
"path": {
38-
"$ref": "viss#/definitions/path"
42+
"$ref": "viss#/definitions/path"
3943
},
4044
"requestId": {
4145
"$ref": "viss#/definitions/requestId"
@@ -51,18 +55,19 @@ static const char* SCHEMA_SET=R"(
5155
"title": "Set Request",
5256
"description": "Enables the client to set one or more values once.",
5357
"type": "object",
54-
"required": ["action", "path", "value", "requestId"],
58+
"required": ["action", "path", "requestId"],
5559
"properties": {
5660
"action": {
5761
"enum": [ "set" ],
5862
"description": "The identifier for the set request"
5963
},
64+
"attribute": {
65+
"enum": [ "targetValue", "value" ],
66+
"description": "The attributes to be fetched for the get request"
67+
},
6068
"path": {
6169
"$ref": "viss#/definitions/path"
6270
},
63-
"value": {
64-
"$ref": "viss#/definitions/value"
65-
},
6671
"requestId": {
6772
"$ref": "viss#/definitions/requestId"
6873
}
@@ -86,6 +91,10 @@ static const char* SCHEMA_SUBSCRIBE=R"(
8691
"path": {
8792
"$ref": "viss#/definitions/path"
8893
},
94+
"attribute": {
95+
"enum": [ "targetValue", "value" ],
96+
"description": "The attributes to be fetched for the get request"
97+
},
8998
"filters": {
9099
"$ref": "viss#/definitions/filters"
91100
},

include/VssCommandProcessor.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class VssCommandProcessor : public IVssCommandProcessor {
5252
const std::string & token);
5353
std::string processGet2(kuksa::kuksaChannel &channel, jsoncons::json &request);
5454
std::string processSet2(kuksa::kuksaChannel &channel, jsoncons::json &request);
55+
std::string processGetTarget(kuksa::kuksaChannel &channel, jsoncons::json &request);
56+
std::string processSetTarget(kuksa::kuksaChannel &channel, jsoncons::json &request);
5557
std::string processSubscribe(kuksa::kuksaChannel& channel, jsoncons::json &request);
5658
std::string processUnsubscribe(kuksa::kuksaChannel &channel, jsoncons::json &request);
5759

include/VssDatabase.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class VssDatabase : public IVssDatabase {
4747
bool pathExists(const VSSPath &path) override;
4848
bool pathIsWritable(const VSSPath &path) override;
4949
bool pathIsReadable(const VSSPath &path) override;
50+
bool pathIsAttributable(const VSSPath &path, const std::string &attr) override;
5051

5152
std::list<VSSPath> getLeafPaths(const VSSPath& path) override;
5253

@@ -66,8 +67,8 @@ class VssDatabase : public IVssDatabase {
6667
void updateMetaData(kuksa::kuksaChannel& channel, const VSSPath& path, const jsoncons::json& newTree) override;
6768
jsoncons::json getMetaData(const VSSPath& path) override;
6869

69-
jsoncons::json setSignal(const VSSPath &path, jsoncons::json &value) override; //gen2 version
70-
jsoncons::json getSignal(const VSSPath &path) override; //Gen2 version
70+
jsoncons::json setSignal(const VSSPath &path, const std::string& attr, jsoncons::json &value) override; //gen2 version
71+
jsoncons::json getSignal(const VSSPath &path, const std::string& attr) override; //Gen2 version
7172

7273
void applyDefaultValues(jsoncons::json &tree, VSSPath currentPath);
7374

include/VssDatabase_Record.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ class VssDatabase_Record : public VssDatabase
2929

3030
boost::log::sources::logger_mt lg;
3131

32-
jsoncons::json setSignal(const VSSPath &path, jsoncons::json &value) override; //gen2 version
33-
jsoncons::json getSignal(const VSSPath &path) override; //Gen2 version
34-
32+
jsoncons::json setSignal(const VSSPath &path, const std::string& attr, jsoncons::json &value) override; //gen2 version
33+
jsoncons::json getSignal(const VSSPath &path, const std::string& attr) override; //Gen2 version
3534

3635
private:
3736

include/interface/ISubscriptionHandler.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ class ISubscriptionHandler {
3737

3838
virtual SubscriptionId subscribe(kuksa::kuksaChannel& channel,
3939
std::shared_ptr<IVssDatabase> db,
40-
const std::string &path) = 0;
40+
const std::string &path, const std::string& attr) = 0;
4141
virtual int unsubscribe(SubscriptionId subscribeID) = 0;
4242
virtual int unsubscribeAll(ConnectionId connectionID) = 0;
43-
virtual int publishForVSSPath(const VSSPath path, const jsoncons::json &value) = 0;
43+
virtual int publishForVSSPath(const VSSPath path, const std::string& attr, const jsoncons::json &value) = 0;
4444

4545
virtual std::shared_ptr<IServer> getServer() = 0;
4646
virtual int startThread() = 0;

include/interface/IVssDatabase.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ class IVssDatabase {
3131
virtual void updateMetaData(kuksa::kuksaChannel& channel, const VSSPath& path, const jsoncons::json& value) = 0;
3232
virtual jsoncons::json getMetaData(const VSSPath &path) = 0;
3333

34-
virtual jsoncons::json setSignal(const VSSPath &path, jsoncons::json &value) = 0; //gen2 version
35-
virtual jsoncons::json getSignal(const VSSPath& path) = 0;
34+
virtual jsoncons::json setSignal(const VSSPath &path, const std::string& attr, jsoncons::json &value) = 0; //gen2 version
35+
virtual jsoncons::json getSignal(const VSSPath& path, const std::string& attr) = 0;
3636

3737
virtual bool pathExists(const VSSPath &path) = 0;
3838
virtual bool pathIsWritable(const VSSPath &path) = 0;
3939
virtual bool pathIsReadable(const VSSPath &path) = 0;
40+
virtual bool pathIsAttributable(const VSSPath &path, const std::string &attr) = 0;
4041

4142
virtual std::list<VSSPath> getLeafPaths(const VSSPath& path) = 0;
4243

kuksa_viss_client/__init__.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,42 +113,44 @@ def getMetaData(self, path, timeout = 1):
113113
return self._sendReceiveMsg(req, timeout)
114114

115115
# Set value to a given path
116-
def setValue(self, path, value, timeout = 1):
116+
def setValue(self, path, value, attribute="value", timeout = 1):
117117
if 'nan' == value:
118118
print(path + " has an invalid value " + str(value))
119119
return
120120
req = {}
121121
req["action"]= "set"
122122
req["path"] = path
123+
req["attribute"] = attribute
123124
try:
124125
jsonValue = json.loads(value)
125126
if isinstance(jsonValue, list):
126-
req["value"] = []
127+
req[attribute] = []
127128
for v in jsonValue:
128-
req["value"].append(str(v))
129+
req[attribute].append(str(v))
129130
else:
130-
req["value"] = str(value)
131+
req[attribute] = str(value)
131132
except json.decoder.JSONDecodeError:
132-
req["value"] = str(value)
133+
req[attribute] = str(value)
133134

134135
return self._sendReceiveMsg(req, timeout)
135136

136-
137137
# Get value to a given path
138-
def getValue(self, path, timeout = 5):
138+
def getValue(self, path, attribute="value", timeout = 5):
139139
req = {}
140-
req["action"]= "get"
140+
req["action"] = "get"
141141
req["path"] = path
142+
req["attribute"] = attribute
142143
return self._sendReceiveMsg(req, timeout)
143144

144145
# Subscribe value changes of to a given path.
145146
# The given callback function will be called then, if the given path is updated:
146147
# updateMessage = await webSocket.recv()
147148
# callback(updateMessage)
148-
def subscribe(self, path, callback, timeout = 5):
149+
def subscribe(self, path, callback, attribute = "value", timeout = 5):
149150
req = {}
150151
req["action"]= "subscribe"
151152
req["path"] = path
153+
req["attribute"] = attribute
152154
res = self._sendReceiveMsg(req, timeout)
153155
resJson = json.loads(res)
154156
if "subscriptionId" in resJson:
@@ -193,7 +195,11 @@ async def _receiver_handler(self, webSocket):
193195
await asyncio.sleep(0.01)
194196
else:
195197
if "subscriptionId" in resJson and resJson["subscriptionId"] in self.subscriptionCallbacks:
196-
self.subscriptionCallbacks[resJson["subscriptionId"]](message)
198+
try:
199+
self.subscriptionCallbacks[resJson["subscriptionId"]](message)
200+
except Exception as e:
201+
print(e)
202+
197203

198204
async def _sender_handler(self, webSocket):
199205
while self.run:

kuksa_viss_client/__main__.py

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ def path_completer(self, text, line, begidx, endidx):
8484

8585
return basic_complete(text, line, begidx, endidx, self.pathCompletionItems)
8686

87-
def subscribeCallback(self, path, resp):
88-
self.subscribeFileDesc[path].write(resp + "\n")
89-
self.subscribeFileDesc[path].flush()
87+
def subscribeCallback(self, path, attr, resp):
88+
print(path, attr)
89+
self.subscribeFileDesc[(path,attr)].write(resp + "\n")
90+
self.subscribeFileDesc[(path,attr)].flush()
9091

9192
def subscriptionIdCompleter(self, text, line, begidx, endidx):
9293
self.pathCompletionItems = []
@@ -113,12 +114,22 @@ def subscriptionIdCompleter(self, text, line, begidx, endidx):
113114
ap_setValue = argparse.ArgumentParser()
114115
ap_setValue.add_argument("Path", help="Path to be set", completer_method=path_completer)
115116
ap_setValue.add_argument("Value", help="Value to be set")
117+
ap_setValue.add_argument("Attribute", help="Attribute to be set", default="value", nargs=(0,1))
116118

117119
ap_getValue = argparse.ArgumentParser()
118120
ap_getValue.add_argument("Path", help="Path to be read", completer_method=path_completer)
121+
ap_getValue.add_argument("Attribute", help="Attribute to be get", default="value", nargs=(0,1))
122+
123+
ap_setTargetValue = argparse.ArgumentParser()
124+
ap_setTargetValue.add_argument("Path", help="Path whose target value to be set", completer_method=path_completer)
125+
ap_setTargetValue.add_argument("Value", help="Value to be set")
126+
127+
ap_getTargetValue = argparse.ArgumentParser()
128+
ap_getTargetValue.add_argument("Path", help="Path whose target value to be read", completer_method=path_completer)
119129

120130
ap_subscribe = argparse.ArgumentParser()
121131
ap_subscribe.add_argument("Path", help="Path to be subscribed", completer_method=path_completer)
132+
ap_subscribe.add_argument("Attribute", help="Attribute to be subscribed", default="value", completer_method=path_completer, nargs=(0,1))
122133

123134
ap_unsubscribe = argparse.ArgumentParser()
124135
ap_unsubscribe.add_argument("SubscribeId", help="Corresponding subscription Id", completer_method=subscriptionIdCompleter)
@@ -170,7 +181,16 @@ def do_authorize(self, args):
170181
def do_setValue(self, args):
171182
"""Set the value of a path"""
172183
if self.checkConnection():
173-
resp = self.commThread.setValue(args.Path, args.Value)
184+
resp = self.commThread.setValue(args.Path, args.Value, args.Attribute)
185+
print(highlight(resp, lexers.JsonLexer(), formatters.TerminalFormatter()))
186+
self.pathCompletionItems = []
187+
188+
@with_category(VISS_COMMANDS)
189+
@with_argparser(ap_setTargetValue)
190+
def do_setTargetValue(self, args):
191+
"""Set the value of a path"""
192+
if self.checkConnection():
193+
resp = self.commThread.setValue(args.Path, args.Value, "targetValue")
174194
print(highlight(resp, lexers.JsonLexer(), formatters.TerminalFormatter()))
175195
self.pathCompletionItems = []
176196

@@ -179,7 +199,16 @@ def do_setValue(self, args):
179199
def do_getValue(self, args):
180200
"""Get the value of a path"""
181201
if self.checkConnection():
182-
resp = self.commThread.getValue(args.Path)
202+
resp = self.commThread.getValue(args.Path, args.Attribute)
203+
print(highlight(resp, lexers.JsonLexer(), formatters.TerminalFormatter()))
204+
self.pathCompletionItems = []
205+
206+
@with_category(VISS_COMMANDS)
207+
@with_argparser(ap_getTargetValue)
208+
def do_getTargetValue(self, args):
209+
"""Get the value of a path"""
210+
if self.checkConnection():
211+
resp = self.commThread.getValue(args.Path, "targetValue")
183212
print(highlight(resp, lexers.JsonLexer(), formatters.TerminalFormatter()))
184213
self.pathCompletionItems = []
185214

@@ -188,12 +217,12 @@ def do_getValue(self, args):
188217
def do_subscribe(self, args):
189218
"""Subscribe the value of a path"""
190219
if self.checkConnection():
191-
resp = self.commThread.subscribe(args.Path, lambda msg: self.subscribeCallback(args.Path, msg))
220+
resp = self.commThread.subscribe(args.Path, lambda msg: self.subscribeCallback(args.Path, args.Attribute, msg), args.Attribute)
192221
resJson = json.loads(resp)
193222
if "subscriptionId" in resJson:
194-
fileName = os.getcwd() + "/log_"+args.Path.replace("/", ".")+"_"+str(time.time())
195-
self.subscribeFileDesc[args.Path] = open(fileName, "w")
196-
self.subscribeIdToPath[resJson["subscriptionId"]] = args.Path
223+
fileName = os.getcwd() + "/log_"+args.Path.replace("/", ".")+"_"+args.Attribute+"_"+str(time.time())
224+
self.subscribeFileDesc[(args.Path, args.Attribute)] = open(fileName, "w")
225+
self.subscribeIdToPath[resJson["subscriptionId"]] = (args.Path, args.Attribute)
197226
print("Subscription log available at " + fileName)
198227
print("Execute tail -f " + fileName + " on another Terminal instance")
199228
from shutil import which
@@ -210,10 +239,10 @@ def do_unsubscribe(self, args):
210239
resp = self.commThread.unsubscribe(args.SubscribeId)
211240
print(highlight(resp, lexers.JsonLexer(), formatters.TerminalFormatter()))
212241
if args.SubscribeId in self.subscribeIdToPath.keys():
213-
path = self.subscribeIdToPath[args.SubscribeId]
242+
(path,attr) = self.subscribeIdToPath[args.SubscribeId]
214243
if path in self.subscribeFileDesc:
215-
self.subscribeFileDesc[path].close()
216-
del(self.subscribeFileDesc[path])
244+
self.subscribeFileDesc[(path,attr)].close()
245+
del(self.subscribeFileDesc[(path,attr)])
217246
del(self.subscribeIdToPath[args.SubscribeId])
218247
self.pathCompletionItems = []
219248

0 commit comments

Comments
 (0)