2 Copyright (C) 2012 Intel Corporation
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.
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.
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
19 #include <boost/assert.hpp>
23 #include <vehicleproperty.h>
24 #include <listplusplus.h>
27 #include <ambplugin.h>
29 #include "cangenplugin.h"
31 //----------------------------------------------------------------------------
33 //----------------------------------------------------------------------------
35 // library exported function for plugin loader
36 extern "C" void create(AbstractRoutingEngine* routingengine, std::map<std::string, std::string> config)
39 DEBUG_CONF("cangenplugin",
40 CUtil::Logger::file_off | CUtil::Logger::screen_on,
41 CUtil::Logger::EInfo, CUtil::Logger::EInfo
45 AmbPlugin<CANGenPlugin> * plugin = new AmbPlugin<CANGenPlugin>(routingengine, config);
49 //----------------------------------------------------------------------------
51 //----------------------------------------------------------------------------
53 CANGenPlugin::CANGenPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
54 AmbPluginImpl(re, config, parent),
55 ws(new WebSockets(*this))
57 addPropertySupport(Zone::None,[]()
59 return new SimCommand();
63 CANGenPlugin::~CANGenPlugin()
65 for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
70 void CANGenPlugin::init()
72 routingEngine->subscribeToProperty("MappingTable", &source);
75 void CANGenPlugin::propertyChanged(AbstractPropertyType* value)
79 if(!value->name.compare("MappingTable")) {
80 parseMappingTable(value->toString());
84 AsyncPropertyReply *CANGenPlugin::setProperty(const AsyncSetPropertyRequest &request)
86 if(request.property == "SimCommand")
88 std::string v = request.value->toString();
90 dataReceived(nullptr, v.c_str(), v.length());
93 return AmbPluginImpl::setProperty(request);
96 void CANGenPlugin::parseMappingTable(const std::string& table)
98 scoped_lock<interprocess_recursive_mutex> lock(mutex);
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);
105 LOG_ERROR("Failed to parse json: " << json);
109 // Success, use json_obj here.
110 mappingTable.clear();
111 json_object *sources = json_object_object_get(rootobject.get(),"sources");
114 array_list* arraySources = json_object_get_array(sources);
117 for(int i=0; i < array_list_length(arraySources); ++i)
119 json_object *rootsource = static_cast<json_object*>(array_list_get_idx(arraySources,i));
122 json_object* source = json_object_object_get(rootsource, "source");
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");
130 array_list* arraySignals = json_object_get_array(signals);
131 for(int j = 0; j < array_list_length(arraySignals); ++j)
133 json_object *signal = static_cast<json_object*>(array_list_get_idx(arraySignals,j));
136 mappingTable.addProperty(guidstr, signal);
137 }// signals array loop
138 }// sources array loop
142 void CANGenPlugin::errorOccured(CANObserver::CANError error)
145 LOG_INFO( "CANPlugin::errorOccured() not implemented "<< std::endl );
148 void CANGenPlugin::standardFrameReceived(const can_frame& frame)
151 LOG_INFO( "CANPlugin::standardFrameReceived() not implemented "<< std::endl );
154 void CANGenPlugin::extendedFrameReceived(const can_frame& frame)
156 LOG_INFO("CANPlugin::extendedFrameReceived()");
160 void CANGenPlugin::errorFrameReceived(const can_frame& frame)
162 LOG_INFO("CANPlugin::errorFrameReceived()");
166 void CANGenPlugin::remoteTransmissionRequest(const can_frame& frame)
169 LOG_INFO( "CANPlugin::remoteTransmissionRequest() not implemented "<< std::endl );
172 void CANGenPlugin::printFrame(const can_frame& frame) const
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 );
177 std::stringstream ss;
178 for(int i=0; i<frame.can_dlc; ++i){
179 ss << " " << std::hex << (int)(frame.data[i]);
183 LOG_INFO( "CANPlugin::printFrame can data" << ss.str() << endl );
186 bool CANGenPlugin::sendValue(const std::string& interface, AbstractPropertyType* value)
188 scoped_lock<interprocess_recursive_mutex> lock(mutex);
192 int can_id = mappingTable.getCanId(value->sourceUuid, value->zone, value->name);
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);
204 auto& canBus = interfaces[interface];
206 canBus = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
207 bool started(canBus->start(interface.c_str()));
211 return canBus->sendExtendedFrame(frame);
214 void CANGenPlugin::getValue(libwebsocket* socket, const std::string& property, int zone, const std::string& id)
216 AsyncPropertyRequest request;
217 PropertyList foo = VehicleProperty::capabilities();
218 if(contains(foo, property))
220 request.property = property;
224 DebugOut(0)<<"websocketsink: Invalid property requested: "<<property;
228 request.zoneFilter = zone;
229 request.completed = [socket,id,property](AsyncPropertyReply* reply)
231 DebugOut()<<"Got property: "<<reply->property.c_str()<<endl;
233 DebugOut()<<"Property value is null"<<endl;
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 << "\"}";
246 string replystr = s.str();
247 //printf("Reply: %s\n",replystr.c_str());
248 LOG_MESSAGE("Reply:" << replystr << endl);
250 //if(replystr.length() > 4096){
251 // WebSockets::Write(socket, replystr.substr(0,4096));
252 // WebSockets::Write(socket, replystr.substr(4096, 4096));
254 //else WebSockets::Write(socket, replystr);
255 WebSockets::Write(socket, replystr);
260 routingEngine->getPropertyAsync(request);
263 void CANGenPlugin::setValue(libwebsocket* socket, const std::string& property, const std::string& value, int zone, const std::string& interface, const std::string& transactionId)
265 LOG_MESSAGE( "CANGenPlugin::setValue called with arguments:" << property << ", " << value << endl);
268 std::unique_ptr<AbstractPropertyType> type(VehicleProperty::getPropertyTypeForPropertyNameValue(property,value));
271 type->sourceUuid = CANSimPluginUUID;
273 sent = sendValue(interface, type.get());
277 ss << "{\"type\":\"methodReply\",\"name\":\"set\",\"data\":[{\"property\":\"" << property << "\"}],\"transactionid\":\"" << transactionId << "\"";
279 ss << ",\"error\":\"method call failed\"";
282 string replystr = ss.str();
283 LOG_MESSAGE( "Reply:" << replystr << endl);
285 WebSockets::Write(socket, replystr);
288 void CANGenPlugin::dataReceived(libwebsocket* socket, const char* data, size_t len)
290 if(!data || len == 0)
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;
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)
303 LOG_ERROR("Error: " << json_tokener_error_desc(err) << std::endl);
308 LOG_ERROR("Failed to parse json: " << data << std::endl);
312 if (tokener->char_offset < len) // XXX shouldn't access internal fields
314 // Handle extra characters after parsed object as desired.
315 // e.g. issue an error, parse another object from that point, etc...
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");
322 if(!typeobject || !nameobject || !transidobject)
324 DebugOut(DebugOut::Warning)<<"Malformed json. aborting"<<endl;
328 string type = string(json_object_get_string(typeobject));
329 string name = string(json_object_get_string(nameobject));
331 if (json_object_get_type(transidobject) == json_type_string)
333 id = string(json_object_get_string(transidobject));
338 strstr << json_object_get_int(transidobject);
341 if (type == "method") {
343 vector<string> propertyNames;
344 list< std::tuple<string, string, string, Zone::Type, string> > propertyData;
346 json_object *dataobject = json_object_object_get(rootobject.get(),"data");
347 if (json_object_get_type(dataobject) == json_type_array)
349 array_list *arraylist = json_object_get_array(dataobject);
350 for (int i=0;i<array_list_length(arraylist);i++)
352 json_object *arrayobject = (json_object*)array_list_get_idx(arraylist,i);
353 if (json_object_get_type(arrayobject) == json_type_object)
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);
367 z = static_cast<Zone::Type>(boost::lexical_cast<int,std::string>(json_object_get_string(zoneobject)));
370 propertyData.push_back(make_tuple(interfacestr, keystr, valuestr, z, sourcestr));
372 else if (json_object_get_type(arrayobject) == json_type_string)
374 string propertyName = string(json_object_get_string(arrayobject));
375 propertyNames.push_back(propertyName);
378 //array_list_free(arraylist);
382 string path = json_object_get_string(dataobject);
385 propertyNames.push_back(path);
388 if (type == "method")
392 if (!propertyNames.empty())
394 //GetProperty is going to be a singleshot sink.
395 getValue(socket,propertyNames.front(),Zone::None,id);
397 else if (!propertyData.empty())
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);
405 LOG_WARNING(" \"get\" method called with no data! Transaction ID:" << id);
408 else if (name == "set")
410 LOG_MESSAGE("set called");
411 if (!propertyNames.empty())
415 else if (!propertyData.empty())
417 for (auto prop = propertyData.begin(); prop != propertyData.end(); ++prop)
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);
424 else if (name == "getSupportedEventTypes")
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())
431 //Send what properties we support
432 PropertyList foo(routingEngine->supported());
433 PropertyList::const_iterator i=foo.cbegin();
434 while (i != foo.cend())
437 typessupported.append("\"").append((*i)).append("\"");
439 typessupported.append(",\"").append((*i)).append("\"");
445 //Send what events a particular property supports
446 PropertyList foo(routingEngine->supported());
447 if (contains(foo,propertyNames.front()))
449 //sinkManager->addSingleShotSink(wsi,data.front(),id);
450 typessupported = "\"get\",\"getSupportedEventTypes\"";
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);
462 DebugOut(0)<<"Unknown method called."<<endl;