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" AbstractSource* 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 std::unique_ptr< AmbPlugin<CANGenPlugin> > plugin(new AmbPlugin<CANGenPlugin>(routingengine, config));
47 return plugin.release();
50 //----------------------------------------------------------------------------
52 //----------------------------------------------------------------------------
54 CANGenPlugin::CANGenPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
55 AmbPluginImpl(re, config, parent),
56 ws(new WebSockets(*this))
58 addPropertySupport(Zone::None,[]()
60 return new SimCommand();
64 CANGenPlugin::~CANGenPlugin()
66 for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
71 void CANGenPlugin::init()
73 routingEngine->subscribeToProperty("MappingTable", &source);
76 void CANGenPlugin::propertyChanged(AbstractPropertyType* value)
80 if(!value->name.compare("MappingTable")) {
81 parseMappingTable(value->toString());
85 AsyncPropertyReply *CANGenPlugin::setProperty(const AsyncSetPropertyRequest &request)
87 if(request.property == "SimCommand")
89 std::string v = request.value->toString();
91 dataReceived(nullptr, v.c_str(), v.length());
94 return AmbPluginImpl::setProperty(request);
97 void CANGenPlugin::parseMappingTable(const std::string& table)
99 scoped_lock<interprocess_recursive_mutex> lock(mutex);
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);
106 LOG_ERROR("Failed to parse json: " << json);
110 // Success, use json_obj here.
111 mappingTable.clear();
112 json_object *sources = json_object_object_get(rootobject.get(),"sources");
115 array_list* arraySources = json_object_get_array(sources);
118 for(int i=0; i < array_list_length(arraySources); ++i)
120 json_object *rootsource = static_cast<json_object*>(array_list_get_idx(arraySources,i));
123 json_object* source = json_object_object_get(rootsource, "source");
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");
131 array_list* arraySignals = json_object_get_array(signals);
132 for(int j = 0; j < array_list_length(arraySignals); ++j)
134 json_object *signal = static_cast<json_object*>(array_list_get_idx(arraySignals,j));
137 mappingTable.addProperty(guidstr, signal);
138 }// signals array loop
139 }// sources array loop
143 void CANGenPlugin::errorOccured(CANObserver::CANError error)
146 LOG_INFO( "CANPlugin::errorOccured() not implemented "<< std::endl );
149 void CANGenPlugin::standardFrameReceived(const can_frame& frame)
152 LOG_INFO( "CANPlugin::standardFrameReceived() not implemented "<< std::endl );
155 void CANGenPlugin::extendedFrameReceived(const can_frame& frame)
157 LOG_INFO("CANPlugin::extendedFrameReceived()");
161 void CANGenPlugin::errorFrameReceived(const can_frame& frame)
163 LOG_INFO("CANPlugin::errorFrameReceived()");
167 void CANGenPlugin::remoteTransmissionRequest(const can_frame& frame)
170 LOG_INFO( "CANPlugin::remoteTransmissionRequest() not implemented "<< std::endl );
173 void CANGenPlugin::printFrame(const can_frame& frame) const
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 );
178 std::stringstream ss;
179 for(int i=0; i<frame.can_dlc; ++i){
180 ss << " " << std::hex << (int)(frame.data[i]);
184 LOG_INFO( "CANPlugin::printFrame can data" << ss.str() << endl );
187 bool CANGenPlugin::sendValue(const std::string& interface, AbstractPropertyType* value)
189 scoped_lock<interprocess_recursive_mutex> lock(mutex);
193 int can_id = mappingTable.getCanId(value->sourceUuid, value->zone, value->name);
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);
205 auto& canBus = interfaces[interface];
207 canBus = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
208 bool started(canBus->start(interface.c_str()));
212 return canBus->sendExtendedFrame(frame);
215 void CANGenPlugin::getValue(libwebsocket* socket, const std::string& property, int zone, const std::string& id)
217 AsyncPropertyRequest request;
218 PropertyList foo = VehicleProperty::capabilities();
219 if(contains(foo, property))
221 request.property = property;
225 DebugOut(0)<<"websocketsink: Invalid property requested: "<<property;
229 request.zoneFilter = zone;
230 request.completed = [socket,id,property](AsyncPropertyReply* reply)
232 DebugOut()<<"Got property: "<<reply->property.c_str()<<endl;
234 DebugOut()<<"Property value is null"<<endl;
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 << "\"}";
247 string replystr = s.str();
248 //printf("Reply: %s\n",replystr.c_str());
249 LOG_MESSAGE("Reply:" << replystr << endl);
251 //if(replystr.length() > 4096){
252 // WebSockets::Write(socket, replystr.substr(0,4096));
253 // WebSockets::Write(socket, replystr.substr(4096, 4096));
255 //else WebSockets::Write(socket, replystr);
256 WebSockets::Write(socket, replystr);
261 routingEngine->getPropertyAsync(request);
264 void CANGenPlugin::setValue(libwebsocket* socket, const std::string& property, const std::string& value, int zone, const std::string& interface, const std::string& transactionId)
266 LOG_MESSAGE( "CANGenPlugin::setValue called with arguments:" << property << ", " << value << endl);
269 std::unique_ptr<AbstractPropertyType> type(VehicleProperty::getPropertyTypeForPropertyNameValue(property,value));
272 type->sourceUuid = CANSimPluginUUID;
274 sent = sendValue(interface, type.get());
278 ss << "{\"type\":\"methodReply\",\"name\":\"set\",\"data\":[{\"property\":\"" << property << "\"}],\"transactionid\":\"" << transactionId << "\"";
280 ss << ",\"error\":\"method call failed\"";
283 string replystr = ss.str();
284 LOG_MESSAGE( "Reply:" << replystr << endl);
286 WebSockets::Write(socket, replystr);
289 void CANGenPlugin::dataReceived(libwebsocket* socket, const char* data, size_t len)
291 if(!data || len == 0)
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;
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)
304 LOG_ERROR("Error: " << json_tokener_error_desc(err) << std::endl);
309 LOG_ERROR("Failed to parse json: " << data << std::endl);
313 if (tokener->char_offset < len) // XXX shouldn't access internal fields
315 // Handle extra characters after parsed object as desired.
316 // e.g. issue an error, parse another object from that point, etc...
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");
323 if(!typeobject || !nameobject || !transidobject)
325 DebugOut(DebugOut::Warning)<<"Malformed json. aborting"<<endl;
329 string type = string(json_object_get_string(typeobject));
330 string name = string(json_object_get_string(nameobject));
332 if (json_object_get_type(transidobject) == json_type_string)
334 id = string(json_object_get_string(transidobject));
339 strstr << json_object_get_int(transidobject);
342 if (type == "method") {
344 vector<string> propertyNames;
345 list< std::tuple<string, string, string, Zone::Type, string> > propertyData;
347 json_object *dataobject = json_object_object_get(rootobject.get(),"data");
348 if (json_object_get_type(dataobject) == json_type_array)
350 array_list *arraylist = json_object_get_array(dataobject);
351 for (int i=0;i<array_list_length(arraylist);i++)
353 json_object *arrayobject = (json_object*)array_list_get_idx(arraylist,i);
354 if (json_object_get_type(arrayobject) == json_type_object)
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);
368 z = static_cast<Zone::Type>(boost::lexical_cast<int,std::string>(json_object_get_string(zoneobject)));
371 propertyData.push_back(make_tuple(interfacestr, keystr, valuestr, z, sourcestr));
373 else if (json_object_get_type(arrayobject) == json_type_string)
375 string propertyName = string(json_object_get_string(arrayobject));
376 propertyNames.push_back(propertyName);
379 //array_list_free(arraylist);
383 string path = json_object_get_string(dataobject);
386 propertyNames.push_back(path);
389 if (type == "method")
393 if (!propertyNames.empty())
395 //GetProperty is going to be a singleshot sink.
396 getValue(socket,propertyNames.front(),Zone::None,id);
398 else if (!propertyData.empty())
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);
406 LOG_WARNING(" \"get\" method called with no data! Transaction ID:" << id);
409 else if (name == "set")
411 LOG_MESSAGE("set called");
412 if (!propertyNames.empty())
416 else if (!propertyData.empty())
418 for (auto prop = propertyData.begin(); prop != propertyData.end(); ++prop)
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);
425 else if (name == "getSupportedEventTypes")
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())
432 //Send what properties we support
433 PropertyList foo(routingEngine->supported());
434 PropertyList::const_iterator i=foo.cbegin();
435 while (i != foo.cend())
438 typessupported.append("\"").append((*i)).append("\"");
440 typessupported.append(",\"").append((*i)).append("\"");
446 //Send what events a particular property supports
447 PropertyList foo(routingEngine->supported());
448 if (contains(foo,propertyNames.front()))
450 //sinkManager->addSingleShotSink(wsi,data.front(),id);
451 typessupported = "\"get\",\"getSupportedEventTypes\"";
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);
463 DebugOut(0)<<"Unknown method called."<<endl;