reverted varianttype
[profile/ivi/automotive-message-broker.git] / plugins / cangenplugin / cangenplugin.cpp
1 /*
2 Copyright (C) 2012 Intel Corporation
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include <boost/assert.hpp>
20 #include <glib.h>
21 #include <deque>
22
23 #include <vehicleproperty.h>
24 #include <listplusplus.h>
25
26 #include <logger.h>
27 #include <ambplugin.h>
28
29 #include "cangenplugin.h"
30
31 //----------------------------------------------------------------------------
32 // CANGenPlugin
33 //----------------------------------------------------------------------------
34
35 // library exported function for plugin loader
36 extern "C" void create(AbstractRoutingEngine* routingengine, std::map<std::string, std::string> config)
37 {
38 #ifndef UNIT_TESTS
39         DEBUG_CONF("cangenplugin",
40                 CUtil::Logger::file_off | CUtil::Logger::screen_on,
41                 CUtil::Logger::EInfo, CUtil::Logger::EInfo
42         );
43 #endif
44
45         AmbPlugin<CANGenPlugin> * plugin = new AmbPlugin<CANGenPlugin>(routingengine, config);
46         plugin->init();
47 }
48
49 //----------------------------------------------------------------------------
50 // CANGenPlugin
51 //----------------------------------------------------------------------------
52
53 CANGenPlugin::CANGenPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
54         AmbPluginImpl(re, config, parent),
55         ws(new WebSockets(*this))
56 {
57         addPropertySupport(Zone::None,[]()
58         {
59                 return new SimCommand();
60         });
61 }
62
63 CANGenPlugin::~CANGenPlugin()
64 {
65         for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
66                 it->second->stop();
67         }
68 }
69
70 void CANGenPlugin::init()
71 {
72         routingEngine->subscribeToProperty("MappingTable", &source);
73 }
74
75 void CANGenPlugin::propertyChanged(AbstractPropertyType* value)
76 {
77         if(!value)
78                 return;
79         if(!value->name.compare("MappingTable")) {
80                 parseMappingTable(value->toString());
81         }
82 }
83
84 AsyncPropertyReply *CANGenPlugin::setProperty(const AsyncSetPropertyRequest &request)
85 {
86         if(request.property == "SimCommand")
87         {
88                 std::string v = request.value->toString();
89
90                 dataReceived(nullptr, v.c_str(), v.length());
91         }
92
93         return AmbPluginImpl::setProperty(request);
94 }
95
96 void CANGenPlugin::parseMappingTable(const std::string& table)
97 {
98         scoped_lock<interprocess_recursive_mutex> lock(mutex);
99
100         std::string json(table);
101         std::replace(json.begin(), json.end(), '\'', '"');// replace all ' to "
102         std::unique_ptr<json_object, decltype(&json_object_put)> rootobject(json_tokener_parse(json.c_str()), &json_object_put);
103         if(!rootobject)
104         {
105                 LOG_ERROR("Failed to parse json: " << json);
106                 return;
107         }
108
109         // Success, use json_obj here.
110         mappingTable.clear();
111         json_object *sources = json_object_object_get(rootobject.get(),"sources");
112         if(!sources)
113                 return;
114         array_list* arraySources = json_object_get_array(sources);
115         if(!arraySources)
116                 return;
117         for(int i=0; i < array_list_length(arraySources); ++i)
118         {
119                 json_object *rootsource = static_cast<json_object*>(array_list_get_idx(arraySources,i));
120                 if(!rootsource)
121                         continue;
122                 json_object* source = json_object_object_get(rootsource, "source");
123                 if(!source)
124                         continue;
125                 json_object* guid = json_object_object_get(source, "guid");
126                 const std::string guidstr(guid ? json_object_get_string(guid) : "");
127                 json_object* signals = json_object_object_get(rootsource, "signals");
128                 if(!signals)
129                         continue;
130                 array_list* arraySignals = json_object_get_array(signals);
131                 for(int j = 0; j < array_list_length(arraySignals); ++j)
132                 {
133                         json_object *signal = static_cast<json_object*>(array_list_get_idx(arraySignals,j));
134                         if(!signal)
135                                 continue;
136                         mappingTable.addProperty(guidstr, signal);
137                 }// signals array loop
138         }// sources array loop
139 }
140
141 // from CANObserver
142 void CANGenPlugin::errorOccured(CANObserver::CANError error)
143 {
144         (void) error;
145         LOG_INFO( "CANPlugin::errorOccured() not implemented "<< std::endl );
146 }
147
148 void CANGenPlugin::standardFrameReceived(const can_frame& frame)
149 {
150         (void) frame;
151         LOG_INFO( "CANPlugin::standardFrameReceived() not implemented "<< std::endl );
152 }
153
154 void CANGenPlugin::extendedFrameReceived(const can_frame& frame)
155 {
156         LOG_INFO("CANPlugin::extendedFrameReceived()");
157         printFrame(frame);
158 }
159
160 void CANGenPlugin::errorFrameReceived(const can_frame& frame)
161 {
162         LOG_INFO("CANPlugin::errorFrameReceived()");
163         printFrame(frame);
164 }
165
166 void CANGenPlugin::remoteTransmissionRequest(const can_frame& frame)
167 {
168         (void) frame;
169         LOG_INFO( "CANPlugin::remoteTransmissionRequest() not implemented "<< std::endl );
170 }
171
172 void CANGenPlugin::printFrame(const can_frame& frame) const
173 {
174         LOG_INFO( "CANPlugin::printFrame can_id: " << std::hex << frame.can_id << std::dec << endl );
175         LOG_INFO( "CANPlugin::printFrame can_dlc: " << int(frame.can_dlc) << endl );
176
177         std::stringstream ss;
178         for(int i=0; i<frame.can_dlc; ++i){
179                 ss << " " << std::hex << (int)(frame.data[i]);
180         }
181         ss << std::dec;
182
183         LOG_INFO( "CANPlugin::printFrame can data" << ss.str() << endl );
184 }
185
186 bool CANGenPlugin::sendValue(const std::string& interface, AbstractPropertyType* value)
187 {
188         scoped_lock<interprocess_recursive_mutex> lock(mutex);
189
190         if(!value)
191                 return false;
192         int can_id = mappingTable.getCanId(value->sourceUuid, value->zone, value->name);
193         if(can_id == 0)
194                 return false;
195
196         can_frame frame;
197         frame.can_id = can_id;
198         std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(value->toVariant(), &g_variant_unref);
199         gsize vs = g_variant_get_size(v.get());
200         assert(vs <= sizeof(frame.data));// Has to be <= 8
201         frame.can_dlc = vs > sizeof(frame.data) ? sizeof(frame.data) : vs;
202         memcpy(frame.data, g_variant_get_data(v.get()), frame.can_dlc);
203
204         auto& canBus = interfaces[interface];
205         if(!canBus){
206                 canBus = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
207                 bool started(canBus->start(interface.c_str()));
208                 if(!started)
209                         return false;
210         }
211         return canBus->sendExtendedFrame(frame);
212 }
213
214 void CANGenPlugin::getValue(libwebsocket* socket, const std::string& property, int zone, const std::string& id)
215 {
216         AsyncPropertyRequest request;
217         PropertyList foo = VehicleProperty::capabilities();
218         if(contains(foo, property))
219         {
220                 request.property = property;
221         }
222         else
223         {
224                 DebugOut(0)<<"websocketsink: Invalid property requested: "<<property;
225                 return;
226         }
227
228         request.zoneFilter = zone;
229         request.completed = [socket,id,property](AsyncPropertyReply* reply)
230         {
231                 DebugOut()<<"Got property: "<<reply->property.c_str()<<endl;
232                 if(!reply->value){
233                         DebugOut()<<"Property value is null"<<endl;
234                         delete reply;
235                         return;
236                 }
237
238                 stringstream s;
239                 s.precision(15);
240
241                 s << "{\"type\":\"methodReply\",\"name\":\"get\",\"data\":{";
242                 s << "\"property\":\"" << property << "\",\"zone\":\"" << reply->value->zone << "\",\"value\":\"" << reply->value->toString() << "\",\"timestamp\":\""<<reply->value->timestamp<<"\",";
243                 s <<"\"sequence\": \""<<reply->value->sequence<<"\"}";
244                 s << ",\"transactionid\":\"" << id << "\"}";
245
246                 string replystr = s.str();
247                 //printf("Reply: %s\n",replystr.c_str());
248                 LOG_MESSAGE("Reply:" << replystr << endl);
249
250                 //if(replystr.length() > 4096){
251                 //    WebSockets::Write(socket, replystr.substr(0,4096));
252                 //    WebSockets::Write(socket, replystr.substr(4096, 4096));
253                 //}
254                 //else WebSockets::Write(socket, replystr);
255                 WebSockets::Write(socket, replystr);
256
257                 delete reply;
258         };
259
260         routingEngine->getPropertyAsync(request);
261 }
262
263 void CANGenPlugin::setValue(libwebsocket* socket, const std::string& property, const std::string& value, int zone, const std::string& interface, const std::string& transactionId)
264 {
265         LOG_MESSAGE( "CANGenPlugin::setValue called with arguments:" << property << ", " << value << endl);
266
267         bool sent(false);
268         std::unique_ptr<AbstractPropertyType> type(VehicleProperty::getPropertyTypeForPropertyNameValue(property,value));
269         if(type) {
270                 type->zone = zone;
271                 type->sourceUuid = CANSimPluginUUID;
272
273                 sent = sendValue(interface, type.get());
274         }
275
276         stringstream ss;
277         ss << "{\"type\":\"methodReply\",\"name\":\"set\",\"data\":[{\"property\":\"" << property << "\"}],\"transactionid\":\"" << transactionId << "\"";
278         if(!sent)
279                 ss << ",\"error\":\"method call failed\"";
280         ss << "}";
281
282         string replystr = ss.str();
283         LOG_MESSAGE( "Reply:" << replystr << endl);
284
285         WebSockets::Write(socket, replystr);
286 }
287
288 void CANGenPlugin::dataReceived(libwebsocket* socket, const char* data, size_t len)
289 {
290         if(!data || len == 0)
291                 return;
292
293         //TODO: refactor ? copied from websocketsink
294         std::unique_ptr<json_object, decltype(&json_object_put)> rootobject(nullptr, &json_object_put);
295         std::unique_ptr<json_tokener, decltype(&json_tokener_free)> tokener(json_tokener_new(), &json_tokener_free);
296         enum json_tokener_error err;
297         do
298         {   std::unique_ptr<json_object, decltype(&json_object_put)> tmpobject(json_tokener_parse_ex(tokener.get(), data, len), &json_object_put);
299                 rootobject.swap(tmpobject);
300         } while ((err = json_tokener_get_error(tokener.get())) == json_tokener_continue);
301         if (err != json_tokener_success)
302         {
303                 LOG_ERROR("Error: " << json_tokener_error_desc(err) << std::endl);
304                 return;
305         }
306         if(!rootobject)
307         {
308                 LOG_ERROR("Failed to parse json: " << data << std::endl);
309                 return;
310         }
311
312         if (tokener->char_offset < len) // XXX shouldn't access internal fields
313         {
314                 // Handle extra characters after parsed object as desired.
315                 // e.g. issue an error, parse another object from that point, etc...
316         }
317         // Success, use jobj here.
318         json_object *typeobject = json_object_object_get(rootobject.get(),"type");
319         json_object *nameobject = json_object_object_get(rootobject.get(),"name");
320         json_object *transidobject = json_object_object_get(rootobject.get(),"transactionid");
321
322         if(!typeobject || !nameobject || !transidobject)
323         {
324                 DebugOut(DebugOut::Warning)<<"Malformed json. aborting"<<endl;
325                 return;
326         }
327
328         string type = string(json_object_get_string(typeobject));
329         string name = string(json_object_get_string(nameobject));
330         string id;
331         if (json_object_get_type(transidobject) == json_type_string)
332         {
333                 id = string(json_object_get_string(transidobject));
334         }
335         else
336         {
337                 stringstream strstr;
338                 strstr << json_object_get_int(transidobject);
339                 id = strstr.str();
340         }
341         if (type == "method") {
342
343                 vector<string> propertyNames;
344                 list< std::tuple<string, string, string, Zone::Type, string> > propertyData;
345
346                 json_object *dataobject = json_object_object_get(rootobject.get(),"data");
347                 if (json_object_get_type(dataobject) == json_type_array)
348                 {
349                         array_list *arraylist = json_object_get_array(dataobject);
350                         for (int i=0;i<array_list_length(arraylist);i++)
351                         {
352                                 json_object *arrayobject = (json_object*)array_list_get_idx(arraylist,i);
353                                 if (json_object_get_type(arrayobject) == json_type_object)
354                                 {
355                                         json_object *interfaceobject = json_object_object_get(arrayobject,"interface");
356                                         json_object *propobject = json_object_object_get(arrayobject,"property");
357                                         json_object *valueobject = json_object_object_get(arrayobject,"value");
358                                         json_object *zoneobject = json_object_object_get(arrayobject,"zone");
359                                         json_object *sourceobject = json_object_object_get(arrayobject,"source");
360                                         string interfacestr = string(interfaceobject ? json_object_get_string(interfaceobject) : "vcan0");
361                                         string keystr = string(propobject ? json_object_get_string(propobject) : "");
362                                         string valuestr = string(valueobject ? json_object_get_string(valueobject): "");
363                                         string sourcestr = string(sourceobject ? json_object_get_string(sourceobject): "");
364                                         Zone::Type z(Zone::None);
365                                         if(zoneobject){
366                                                 try {
367                                                         z = static_cast<Zone::Type>(boost::lexical_cast<int,std::string>(json_object_get_string(zoneobject)));
368                                                 } catch (...) { }
369                                         }
370                                         propertyData.push_back(make_tuple(interfacestr, keystr, valuestr, z, sourcestr));
371                                 }
372                                 else if (json_object_get_type(arrayobject) == json_type_string)
373                                 {
374                                         string propertyName = string(json_object_get_string(arrayobject));
375                                         propertyNames.push_back(propertyName);
376                                 }
377                         }
378                         //array_list_free(arraylist);
379                 }
380                 else
381                 {
382                         string path = json_object_get_string(dataobject);
383                         if (path != "")
384                         {
385                                 propertyNames.push_back(path);
386                         }
387                 }
388                 if (type == "method")
389                 {
390                         if (name == "get")
391                         {
392                                 if (!propertyNames.empty())
393                                 {
394                                         //GetProperty is going to be a singleshot sink.
395                                         getValue(socket,propertyNames.front(),Zone::None,id);
396                                 }
397                                 else if (!propertyData.empty())
398                                 {
399                                         //GetProperty is going to be a singleshot sink.
400                                         auto prop = propertyData.front();
401                                         getValue(socket,std::get<1>(prop),std::get<3>(prop),id);
402                                 }
403                                 else
404                                 {
405                                         LOG_WARNING(" \"get\" method called with no data! Transaction ID:" << id);
406                                 }
407                         }
408                         else if (name == "set")
409                         {
410                                 LOG_MESSAGE("set called");
411                                 if (!propertyNames.empty())
412                                 {
413                                         //Should not happen
414                                 }
415                                 else if (!propertyData.empty())
416                                 {
417                                         for (auto prop = propertyData.begin(); prop != propertyData.end(); ++prop)
418                                         {
419                                                 LOG_MESSAGE("websocketsinkmanager setting " << std::get<1>(*prop) << " to " << std::get<2>(*prop) << " in zone " << std::get<3>(*prop));
420                                                 setValue(socket,std::get<1>(*prop),std::get<2>(*prop),std::get<3>(*prop),std::get<0>(*prop), id);
421                                         }
422                                 }
423                         }
424                         else if (name == "getSupportedEventTypes")
425                         {
426                                 //If data.front() dosen't contain a property name, return a list of properties supported.
427                                 //if it does, then return the event types that particular property supports.
428                                 string typessupported = "";
429                                 if (propertyNames.empty())
430                                 {
431                                         //Send what properties we support
432                                         PropertyList foo(routingEngine->supported());
433                                         PropertyList::const_iterator i=foo.cbegin();
434                                         while (i != foo.cend())
435                                         {
436                                                 if(i==foo.cbegin())
437                                                         typessupported.append("\"").append((*i)).append("\"");
438                                                 else
439                                                         typessupported.append(",\"").append((*i)).append("\"");
440                                                 ++i;
441                                         }
442                                 }
443                                 else
444                                 {
445                                         //Send what events a particular property supports
446                                         PropertyList foo(routingEngine->supported());
447                                         if (contains(foo,propertyNames.front()))
448                                         {
449                                                 //sinkManager->addSingleShotSink(wsi,data.front(),id);
450                                                 typessupported = "\"get\",\"getSupportedEventTypes\"";
451                                         }
452                                 }
453                                 stringstream s;
454                                 string s2;
455                                 s << "{\"type\":\"methodReply\",\"name\":\"getSupportedEventTypes\",\"data\":[" << typessupported << "],\"transactionid\":\"" << id << "\"}";
456                                 string replystr = s.str();
457                                 LOG_INFO(" JSON Reply: " << replystr);
458                                 WebSockets::Write(socket, replystr);
459                         }
460                         else
461                         {
462                                 DebugOut(0)<<"Unknown method called."<<endl;
463                         }
464                 }
465         }
466 }