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