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
20 #include "bluemonkey.h"
21 #include "abstractroutingengine.h"
22 #include "ambplugin.h"
25 #include <QJsonDocument>
35 #define foreach Q_FOREACH
37 typedef std::map<std::string, QObject*> create_bluemonkey_module_t(std::map<std::string, std::string> config, QObject* parent);
39 extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config)
41 auto plugin = new AmbPlugin<BluemonkeySink>(routingengine, config);
47 QVariant gvariantToQVariant(GVariant *value)
49 GVariantClass c = g_variant_classify(value);
50 if(c == G_VARIANT_CLASS_BOOLEAN)
51 return QVariant((bool) g_variant_get_boolean(value));
53 else if(c == G_VARIANT_CLASS_BYTE)
54 return QVariant((char) g_variant_get_byte(value));
56 else if(c == G_VARIANT_CLASS_INT16)
57 return QVariant((int) g_variant_get_int16(value));
59 else if(c == G_VARIANT_CLASS_UINT16)
60 return QVariant((unsigned int) g_variant_get_uint16(value));
62 else if(c == G_VARIANT_CLASS_INT32)
63 return QVariant((int) g_variant_get_int32(value));
65 else if(c == G_VARIANT_CLASS_UINT32)
66 return QVariant((unsigned int) g_variant_get_uint32(value));
68 else if(c == G_VARIANT_CLASS_INT64)
69 return QVariant((long long) g_variant_get_int64(value));
71 else if(c == G_VARIANT_CLASS_UINT64)
72 return QVariant((unsigned long long) g_variant_get_uint64(value));
74 else if(c == G_VARIANT_CLASS_DOUBLE)
75 return QVariant(g_variant_get_double(value));
77 else if(c == G_VARIANT_CLASS_STRING)
78 return QVariant(g_variant_get_string(value, NULL));
80 else if(c == G_VARIANT_CLASS_ARRAY)
82 gsize dictsize = g_variant_n_children(value);
84 for (int i=0;i<dictsize;i++)
86 GVariant *childvariant = g_variant_get_child_value(value,i);
87 GVariant *innervariant = g_variant_get_variant(childvariant);
88 list.append(gvariantToQVariant(innervariant));
94 return QVariant::Invalid;
98 BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent): QObject(0), AmbPluginImpl(e, config, parent), engine(nullptr), mSilentMode(false)
100 QTimer::singleShot(1,this,SLOT(reloadEngine()));
102 auth = new Authenticate(config, this);
104 qmlRegisterType<QTimer>("", 1, 0, "QTimer");
105 qmlRegisterType<QObject>("", 1, 0, "QObject");
109 PropertyList BluemonkeySink::subscriptions()
114 void BluemonkeySink::supportedChanged(const PropertyList & supportedProperties)
116 DebugOut()<<"supported changed"<<endl;
119 void BluemonkeySink::propertyChanged(AbstractPropertyType * value)
124 const string BluemonkeySink::uuid() const
129 int BluemonkeySink::supportedOperations()
131 return AbstractSource::Get | AbstractSource::Set;
134 QObject *BluemonkeySink::subscribeTo(QString str)
136 return new Property(str.toStdString(), "", routingEngine, Zone::None, this);
139 QObject *BluemonkeySink::subscribeToSource(QString str, QString srcFilter)
141 return new Property(str.toStdString(), srcFilter, routingEngine, Zone::None, this);
144 QObject* BluemonkeySink::subscribeToZone(QString str, int zone)
146 return new Property(str.toStdString(), "", routingEngine, zone, this);
150 QStringList BluemonkeySink::sourcesForProperty(QString property)
152 std::list<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
154 for(auto itr = list.begin(); itr != list.end(); itr++)
156 strList<<(*itr).c_str();
162 QStringList BluemonkeySink::supportedProperties()
164 PropertyList props = routingEngine->supported();
175 bool BluemonkeySink::authenticate(QString pass)
180 void BluemonkeySink::loadConfig(QString str)
183 if(!file.open(QIODevice::ReadOnly))
185 DebugOut(DebugOut::Error)<<"failed to open config file: "<<str.toStdString()<<endl;
189 QString script = file.readAll();
193 DebugOut()<<"evaluating script: "<<script.toStdString()<<endl;
195 QJSValue val = engine->evaluate(script);
197 DebugOut()<<val.toString().toStdString()<<endl;
200 bool BluemonkeySink::loadModule(QString path)
202 void* handle = dlopen(path.toUtf8().data(), RTLD_LAZY);
206 DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << dlerror() << endl;
210 void* c = dlsym(handle, "create");
214 DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << path.toStdString() << " " << dlerror() << endl;
218 create_bluemonkey_module_t* create = (create_bluemonkey_module_t*)(c);
220 std::map<std::string, QObject*> exports = create(configuration, this);
222 for(auto i : exports)
224 QJSValue val = engine->newQObject(i.second);
225 engine->globalObject().setProperty(i.first.c_str(), val);
231 void BluemonkeySink::reloadEngine()
234 engine->deleteLater();
236 engine = new QJSEngine(this);
238 QJSValue value = engine->newQObject(this);
239 engine->globalObject().setProperty("bluemonkey", value);
241 loadConfig(configuration["config"].c_str());
244 void BluemonkeySink::writeProgram(QString program)
248 QJSValue result = temp.evaluate(program);
251 DebugOut(DebugOut::Error)<<"Syntax error in program: "<<result.toString().toStdString()<<endl;
255 QFile file(configuration["customPrograms"].c_str());
257 if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
259 DebugOut(DebugOut::Error)<<"failed to open file: "<<file.fileName().toStdString()<<endl;
263 file.write(program.toUtf8());
269 void BluemonkeySink::log(QString str)
271 DebugOut()<<str.toStdString()<<endl;
274 QObject *BluemonkeySink::createTimer()
276 return new QTimer(this);
279 QObject *BluemonkeySink::createQObject()
281 return new QObject(this);
284 void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction)
286 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
287 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
288 AsyncRangePropertyRequest request;
289 request.timeBegin = b;
292 PropertyList reqlist;
294 foreach(QString prop, properties)
296 reqlist.push_back(prop.toStdString());
299 request.properties = reqlist;
300 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
304 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
308 if(cbFunction.isCallable())
312 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
314 AbstractPropertyType *val = *itr;
316 list.append(gvariantToQVariant(val->toVariant()));
319 QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
321 cbFunction.call(QJSValueList()<<val);
328 routingEngine->getRangePropertyAsync(request);
331 void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, int zone)
333 QVariant var = defaultValue.toVariant();
335 auto create = [defaultValue, name, var]() -> AbstractPropertyType*
340 if(var.type() == QVariant::UInt)
341 return new BasicPropertyType<uint>(name.toStdString(), var.toUInt());
342 else if(var.type() == QVariant::Double)
343 return new BasicPropertyType<double>(name.toStdString(), var.toDouble());
344 else if(var.type() == QVariant::Bool)
345 return new BasicPropertyType<bool>(name.toStdString(), var.toBool());
346 else if(var.type() == QVariant::Int)
347 return new BasicPropertyType<int>(name.toStdString(), var.toInt());
348 else if(var.type() == QVariant::String)
349 return new StringPropertyType(name.toStdString(), var.toString().toStdString());
354 addPropertySupport(zone, create);
356 AsyncSetPropertyRequest request;
357 request.property = name.toStdString();
358 request.zoneFilter = zone;
359 request.value = VehicleProperty::getPropertyTypeForPropertyNameValue(name.toStdString(), var.toString().toStdString());
361 routingEngine->updateSupported(supported(), PropertyList(), &source);
362 routingEngine->setProperty(request);
366 QVariant Property::value()
368 return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
371 void Property::setValue(QVariant v)
373 if(v.type() == QVariant::List || v.type() == QVariant::Map)
376 QJsonDocument doc = QJsonDocument::fromVariant(v);
378 QString json = doc.toJson();
380 mValue->fromString(json.toStdString());
384 QString tempVal = v.toString();
385 mValue->fromString(tempVal.toStdString());
388 AsyncSetPropertyRequest request;
389 request.property = mValue->name;
390 request.value = mValue->copy();
391 request.completed = [&](AsyncPropertyReply* reply)
395 propertyChanged(reply->value);
399 DebugOut(DebugOut::Warning) << "Error, trying to set value: " << reply->error << endl;
403 routingEngine->setProperty(request);
406 void Property::getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction)
408 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
409 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
410 AsyncRangePropertyRequest request;
411 request.timeBegin = b;
414 PropertyList reqlist;
415 reqlist.push_back(mValue->name);
417 request.properties = reqlist;
418 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
422 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
426 if(cbFunction.isCallable())
430 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
432 AbstractPropertyType *val = *itr;
434 list.append(gvariantToQVariant(val->toVariant()));
436 QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
437 cbFunction.call(QJSValueList()<<val);
444 routingEngine->getRangePropertyAsync(request);
447 Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, Zone::Type zone, QObject *parent)
448 :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid()), mZone(zone)
450 setType(prop.c_str());
453 QString Property::type()
455 return mValue->name.c_str();
458 void Property::setType(QString t)
460 if(mValue && type() != "")
461 routingEngine->unsubscribeToProperty(type().toStdString(), this);
463 routingEngine->subscribeToProperty(t.toStdString(), this);
465 mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
470 AsyncPropertyRequest request;
471 request.property = mValue->name;
472 request.completed = [this](AsyncPropertyReply* reply)
475 propertyChanged(reply->value);
480 routingEngine->getPropertyAsync(request);
483 void Property::propertyChanged(AbstractPropertyType *value)
485 if(value->zone != mZone)
492 mValue = value->copy();
494 changed(gvariantToQVariant(mValue->toVariant()));
498 QVariant BluemonkeySink::zonesForProperty(QString prop, QString src)
500 PropertyInfo info = routingEngine->getPropertyInfo(prop.toStdString(), src.toStdString());
504 for(auto i : info.zones())