project(automotive-message-broker)
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_BUILD_TYPE, Debug)
option(usebluez5 "use bluez 5 API" OFF)
option(xwalk_vehicle_extension "Crosswalk vehicle extension" OFF)
set(XWALK_EXTENSION_PATH "/automotive-message-broker/xwalk" CACHE PATH "directory the xwalk extension will be installed to")
+set(QMAKE_INSTALL_PATH "/usr/bin/qmake" CACHE PATH "qmake executable path")
#turn on -fpic/-fpie:
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
~~~~~~~~~~~~~{.json}
{
- "mainloop" : "/usr/lib/x86_64-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
+ "mainloop" : "/usr/lib/i386-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
"plugins" : "/etc/ambd/plugins.d"
}
~~~~~~~~~~~~~
message(STATUS "enabling bluemonkey plugin")
set(qtmainloop ON CACHE INTERNAL "")
+set(CMAKE_PREFIX_PATH "${QMAKE_INSTALL_PATH}")
+
+message(STATUS "using path: ${CMAKE_PREFIX_PATH}")
find_package(Qt5Core REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Qml REQUIRED)
if(Qt5Core_FOUND)
+ message(STATUS "qt version: ${QMAKE_INSTALL_PATH}/include/QtCore/${Qt5Core_VERSION}/QtCore")
set(QT_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS})
set(QT_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5Network_LIBRARIES} ${Qt5Qml_LIBRARIES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
if(Qt5DBus_FOUND)
message(STATUS "enabling dbus bluemonkey module")
- add_library(bluemonkeyDBusModule MODULE bmdbus.cpp)
+ set(QT_INCLUDE_DIRS ${QT_INCLUDE_DIRS} ${QMAKE_INSTALL_PATH}/include/QtCore/${Qt5Core_VERSION}/QtCore)
+ add_executable(bluemonkeyDBusModule bmdbus.cpp)
set_target_properties(bluemonkeyDBusModule PROPERTIES PREFIX "")
+ set_target_properties(bluemonkeyDBusModule PROPERTIES SUFFIX ".so")
target_link_libraries(bluemonkeyDBusModule ${link_libraries} amb -L${CMAKE_CURRENT_BINARY_DIR}/lib ${QT_LIBRARIES} ${Qt5DBus_LIBRARIES})
set(QT_INCLUDE_DIRS ${QT_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS})
- install(TARGETS bluemonkeyDBusModule LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
+ install(TARGETS bluemonkeyDBusModule RUNTIME DESTINATION ${PLUGIN_INSTALL_PATH})
endif()
-include_directories(${CMAKE_SOURCE_DIR}/lib ${include_dirs} ${communi_INCLUDE_DIRS} ${QT_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/plugins/common)
+include_directories(${CMAKE_SOURCE_DIR}/lib ${include_dirs} ${communi_INCLUDE_DIRS} ${QT_INCLUDE_DIRS} ${QT_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/plugins/common)
set(bluemonkeyplugin_headers bluemonkey.h authenticate.h)
set(bluemonkeyplugin_sources bluemonkey.cpp authenticate.cpp)
#define foreach Q_FOREACH
-typedef std::map<std::string, QObject*> create_bluemonkey_module_t(std::map<std::string, std::string> config, QObject* parent);
+typedef void create_bluemonkey_module_t(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &javascript, QObject* parent);
extern "C" void create(AbstractRoutingEngine* routingengine, map<string, string> config)
{
create_bluemonkey_module_t* create = (create_bluemonkey_module_t*)(c);
- std::map<std::string, QObject*> exports = create(configuration, this);
+ std::map<std::string, QObject*> exports;
+ QString js;
+ create(configuration, exports, js, this);
for(auto i : exports)
{
- loadModule(i.first, i.second);
+ QObject* obj = i.second;
+ loadModule(i.first, obj);
}
+ engine->evaluate(js);
+
return true;
}
QJSValue value = engine->newQObject(this);
engine->globalObject().setProperty("bluemonkey", value);
- QThread* thread = new QThread(this);
-
- engine->moveToThread(thread);
+ //engine->moveToThread(thread);
thread->start();
if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
{
- DebugOut(DebugOut::Error)<<"failed to open file: "<<file.fileName().toStdString()<<endl;
+ DebugOut(DebugOut::Error) << "failed to open file: " << file.fileName().toStdString() << endl;
return;
}
Bluemonkey::Bluemonkey(std::map<string, string> config, QObject *parent)
:QObject(parent), engine(nullptr), configuration(config)
{
+ thread = new QThread(this);
QTimer::singleShot(1,this,SLOT(reloadEngine()));
}
engine->globalObject().setProperty(obj.c_str(), val);
}
}
+
+
+void Bluemonkey::assertIsTrue(bool isTrue, const QString & msg)
+{
+ if(!isTrue)
+ log(msg);
+
+ Q_ASSERT(isTrue);
+}
bool loadModule(const string &name, QObject* module);
public Q_SLOTS:
+ void assertIsTrue(bool isTrue, const QString &msg="");
+
void loadConfig(QString str);
bool loadModule(QString path);
void ready();
private:
-
+ QThread* thread;
QList<void*> modules;
QJSEngine* engine;
QStringList configsToLoad;
#include <QDBusInterface>
#include <QDBusConnection>
+#include <QDBusReply>
+#include <QCoreApplication>
+#include <QMetaMethod>
-extern "C" std::map<std::string, QObject*> create(std::map<std::string, std::string> config, QObject* parent)
+#include "bmdbus_p.h"
+
+extern "C" std::map<std::string, QObject*> create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
{
- std::map<std::string, QObject*> moduleInstances;
- moduleInstances["dbus"] = new BMDBus(parent);
- return moduleInstances;
+
+ exports["dbus"] = new BMDBus(parent);
+ exports["testExport"] = new TestQObject(parent);
+
+ js += "dbus.defineMethodSignature = function(obj, methodName, retType, args)"
+ "{"
+ " metadata = obj['_metadata'];"
+ " if(!metadata)"
+ " metadata = new Object;"
+ " metadata[methodName] = {'retType' : retType, 'signature' : args};"
+ " obj['_metadata'] = metadata;"
+ "}";
+
}
BMDBus::BMDBus(QObject *parent)
QObject *BMDBus::createInterface(const QString &service, const QString &path, const QString &interface, BMDBus::Connection bus)
{
- return new QDBusInterface(service, path, interface, bus == Session ? QDBusConnection::sessionBus() : QDBusConnection::systemBus(), this);
+ return new QDBusInterface(service, path, interface, getConnection(bus), this);
}
+bool BMDBus::registerService(const QString &service, BMDBus::Connection bus)
+{
+ QDBusConnection con = getConnection(bus);
+
+ return con.registerService(service);
+}
-bool BMDBus::exportObject(const QString &path, const QString &interface, BMDBus::Connection bus, QObject * object)
+bool BMDBus::unregisterService(const QString &service, BMDBus::Connection bus)
{
- QDBusConnection con = bus == Session ? QDBusConnection::sessionBus( ): QDBusConnection::systemBus();
+ QDBusConnection con = getConnection(bus);
+
+ return con.unregisterService(service);
+}
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
- con.registerObject(path, interface, object, QDBusConnection::ExportAllContents);
+
+bool BMDBus::exportObject(const QString &path, const QString &interface, BMDBus::Connection bus, const QJSValue &object)
+{
+ if(!object.isObject())
+ return false;
+/*
+ QDBusConnection con = getConnection(bus);
+/// TODO: should be qt 5.5:
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 1))
+ return con.registerObject(path, interface, object, QDBusConnection::ExportAllContents);
#else
DebugOut(DebugOut::Warning) << "BMDBus::exportObject() interface is ignored in qt 5.4 and lower" << endl;
- con.registerObject(path, object, QDBusConnection::ExportAllContents);
+ return con.registerObject(path, object, QDBusConnection::ExportAllContents);
#endif
+*/
+}
+
+QString BMDBus::errorMessage(const BMDBus::Connection bus)
+{
+ QDBusConnection con = getConnection(bus);
+
+ QDBusError err = con.lastError();
+
+ return err.name() + "(" +QString::number(err.type()) + ") : " + err.message();
+}
+
+QDBusConnection BMDBus::getConnection(const BMDBus::Connection bus)
+{
+ QDBusConnection con = bus == BMDBus::Session ? QDBusConnection::sessionBus() : QDBusConnection::systemBus();
+
+ return con;
+}
+
+
+
+BluemonkeyQObjectPrivate::BluemonkeyQObjectPrivate(BluemonkeyQObject *iface)
+{
+
+}
+
+QVariant BluemonkeyQObjectPrivate::property(const QByteArray &property)
+{
+
+}
+
+bool BluemonkeyQObjectPrivate::setProperty(const QByteArray &property, const QVariant &value)
+{
+
+}
+
+void BluemonkeyQObjectPrivate::createFrom(const QJSValue &value)
+{
+ if(!value.isObject() || !value.hasProperty("_metadata"))
+ {
+ DebugOut(DebugOut::Warning) << "No metadata or not object" << endl;
+ return;
+ }
+
+ QVariantMap metaData = value.property("_metadata").toVariant().toMap();
+
+ Q_FOREACH(QString key, metaData.keys())
+ {
+ QString methodName = key;
+ QVariantMap metaMethod = metaData[key].toMap();
+
+ QStringList args = metaMethod["args"].toStringList();
+ QString returnType = metaMethod["retType"].toString();
+ metaObject->addMethod();
+ }
+
+}
+
+BluemonkeyMetaObject::BluemonkeyMetaObject(BluemonkeyQObject *qq, BluemonkeyQObjectPrivate *dd, const QMetaObject *mo)
+ :q(qq), d(dd)
+{
+ m_builder.setSuperClass(mo);
+ m_builder.setClassName(mo->className());
+ m_builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+
+ m_metaObject = m_builder.toMetaObject();
+
+ QObjectPrivate* op = QObjectPrivate::get(q);
+ m_parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+ *static_cast<QMetaObject*>(this) = *m_metaObject;
+ op->metaObject = this;
+}
+
+BluemonkeyMetaObject::~BluemonkeyMetaObject()
+{
+ delete m_metaObject;
+}
+
+void BluemonkeyMetaObject::updateProperties(const QVariantMap &data)
+{
+ Q_FOREACH(QString key, data.keys())
+ {
+ int i = m_propertyIdLookup.value(key.toUtf8());
+ activate(q, i + m_metaObject->methodOffset(), 0);
+ }
+}
+
+void BluemonkeyMetaObject::addProperty(const QByteArray& name, const QJSValue& property)
+{
+ int id = m_builder.propertyCount();
+ m_builder.addSignal("__"+QByteArray::number(id)+"()");
+ m_propertyIdLookup.insert(name, id);
+ QMetaType::Type propertyType = jsType(property);
+ m_propertyTypeLookup.insert(name, propertyType);
+}
+
+void BluemonkeyMetaObject::addMethod(const QByteArray& name, const QString & returnType, const QStringList &args)
+{
+ if(!method.isCallable()) return;
+
+ if(returnType.isEmpty())
+ returnType = "void";
+
+
+}
+
+QMetaType::Type BluemonkeyMetaObject::jsType(const QJSValue &value)
+{
+ int type = 0;
+ if(value.isArray())
+ {
+ type = qMetaTypeId<QVariantList>();
+ }
+ else if(value.isBool())
+ {
+ type = qMetaTypeId<bool>();
+ }
+ else if(value.isDate())
+ {
+ type = qMetaTypeId<QDateTime>();
+ }
+ else if(value.isNumber())
+ {
+ type = qMetaTypeId<double>();
+ }
+ else if(value.isObject())
+ {
+ type = qMetaTypeId<BluemonkeyQObject*>();
+ }
+ else if(value.isQObject())
+ {
+ type = qMetaTypeId<QObject*>();
+ }
+ else if(value.isString())
+ {
+ type = qMetaTypeId<QString>();
+ }
+ else if(value.isVariant())
+ {
+ type = qMetaTypeId<QVariant>();
+ }
+}
+
+int BluemonkeyMetaObject::metaCall(QMetaObject::Call _c, int _id, void **_a)
+{
+
+}
+
+int BluemonkeyMetaObject::createProperty(const char *, const char *)
+{
+
+}
+
+
+BluemonkeyQObject::BluemonkeyQObject(QObject *parent)
+ :QObject(*new BluemonkeyQObjectPrivate(this), parent)
+{
+ Q_D(BluemonkeyQObject);
+ d->metaObject = new BluemonkeyMetaObject(this, d, metaObject());
+}
+
+int main(int argc, char** argv)
+{
+ DebugOut::setDebugThreshhold(7);
+
+ DebugOut() << "Started BMDBus test " PROJECT_VERSION << endl;
+
+ QCoreApplication app(argc, argv);
+
+ BMDBus dbus;
+
+ dbus.registerService("org.bluemonkey.test", BMDBus::Session);
+/* dbus.exportObject("/testQObject", "org.awesome.interface", BMDBus::Session, new TestQObject(&dbus));
+ dbus.exportObject("/bareQObject", "org.awesome.interface2", BMDBus::Session, new BareQObject());
+
+ QDBusInterface* iface = static_cast<QDBusInterface*>(dbus.createInterface("org.bluemonkey.test", "/testQObject", "org.awesome.interface", BMDBus::Session));
+
+ QDBusReply<QString> reply = iface->call("awesomeMethod");
+
+ DebugOut() << "Reply value: " << reply.value().toStdString() << endl;
+*/
+ app.exec();
}
#define BM_DBUS_H_
#include <QObject>
+#include <QJSValue>
+#include <QDBusConnection>
class BMDBus : public QObject
{
Q_OBJECT
- Q_ENUMS(Connection)
+ Q_PROPERTY(int Session READ sessionBus)
+ Q_PROPERTY(int System READ systemBus)
public:
enum Connection{
- System,
+ System=0,
Session
};
+ Q_ENUMS(Connection)
+
BMDBus(QObject * parent = nullptr);
+ Connection sessionBus() { return BMDBus::Session; }
+ Connection systemBus() { return BMDBus::System; }
+
public Q_SLOTS:
QObject* createInterface(const QString & service, const QString & path, const QString & interface, Connection bus);
- bool exportObject(const QString & path, const QString & interface, Connection bus, QObject *obj);
+ bool registerService(const QString & service, Connection bus);
+
+ bool unregisterService(const QString & service, Connection bus);
+
+ bool exportObject(const QString & path, const QString & interface, Connection bus, const QJSValue &obj);
+
+ QJSValue defineMethodSignature(const QJSValue & obj, const QString & methodName, const QString & returnType, const QStringList & arguments);
+
+ QString errorMessage(const Connection bus = Session);
private: ///methods:
+ QDBusConnection getConnection(const Connection bus);
+};
+
+class BluemonkeyQObjectPrivate;
+class BluemonkeyQObject : public QObject
+{
+ Q_OBJECT
+public:
+ BluemonkeyQObject(QObject* parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(BluemonkeyQObject)
+ Q_DISABLE_COPY(BluemonkeyQObject)
+};
+
+Q_DECLARE_METATYPE(BluemonkeyQObject*)
+class BareQObject : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ void becauseImHappy() { }
};
+class TestQObject : public QObject
+{
+ Q_OBJECT
+public:
+ TestQObject(QObject * parent = nullptr) : QObject(parent) {}
+public Q_SLOTS:
+ QString awesomeMethod() { return "awesome"; }
+};
#endif
--- /dev/null
+#ifndef _BMDBUS_P_H_
+#define _BMDBUS_P_H_
+
+#include <QJSValue>
+#include <QHash>
+
+#include <private/qobject_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+
+class BluemonkeyQObject;
+class BluemonkeyMetaObject;
+class BluemonkeyQObjectPrivate : public QObjectPrivate
+{
+public:
+ BluemonkeyQObjectPrivate(BluemonkeyQObject* iface);
+
+ virtual ~BluemonkeyQObjectPrivate() {}
+
+ QVariant property(const QByteArray& property);
+ bool setProperty(const QByteArray& property, const QVariant& value);
+
+ void createFrom(const QJSValue & value);
+
+ BluemonkeyQObject* q;
+ BluemonkeyMetaObject* metaObject;
+};
+
+class BluemonkeyMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ BluemonkeyMetaObject(BluemonkeyQObject* qq, BluemonkeyQObjectPrivate* dd,
+ const QMetaObject* mo);
+ ~BluemonkeyMetaObject();
+
+ void updateProperties(const QVariantMap & data);
+
+private:
+ void addProperty(const QByteArray & name, const QJSValue & property);
+ void addMethod(const QByteArray & name, const QString &returnType, const QStringList &args);
+
+ QMetaType::Type jsType(const QJSValue& value);
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void** _a);
+ virtual int createProperty(const char *, const char *);
+
+private:
+ BluemonkeyQObject *q;
+ BluemonkeyQObjectPrivate *d;
+
+ QMetaObjectBuilder m_builder;
+ QMetaObject* m_metaObject;
+ QAbstractDynamicMetaObject* m_parent;
+
+ int m_propertyOffset;
+ int m_methodOffset;
+
+ QHash<QByteArray, int> m_propertyIdLookup;
+ QHash<QByteArray, QMetaType::Type> m_propertyTypeLookup;
+ QHash<QByteArray, int> m_methodIdLookup;
+
+ friend class BluemonkeyQObjectPrivate;
+};
+
+#endif
dbusConnected = amb.subscribeTo("DBusConnected");
dbusConnected.changed.connect(function () {
- if(dbusConnected.value !== true)
- return;
+ if(dbusConnected.value !== true)
+ return;
- amb.exportInterface("Bluemonkey",[{'BluemonkeySuperProperty' : 'SuperProperty'},
- {'AnswerToTheUniverse' : 'AnswerToTheUniverse'}]);
+ amb.exportInterface("Bluemonkey",[{'BluemonkeySuperProperty' : 'SuperProperty'},
+ {'AnswerToTheUniverse' : 'AnswerToTheUniverse'}]);
});
bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDBusModule.so");
+exportObj = bluemonkey.createQObject();
+exportObj.foo = function() { return "bar"; }
+exportObj.bar = true;
+
+testExport.jsFunc = function() { return "js rules!"; }
+
if(dbus)
{
- var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
+ try
+ {
+ var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
+
+ var reply = dbusIface.GetId();
+
+ bluemonkey.log("org.freedesktop.DBus.GetId() response: " + reply);
+
+ var registered = dbus.registerService("org.bluemonkey", dbus.Session)
+
+ bluemonkey.assertIsTrue(registered, "could not register service: " + dbus.errorMessage(dbus.Session));
+
+ for(prop in exportObj)
+ {
+ bluemonkey.log(prop +"="+ exportObj[prop]);
+ }
+ for(prop in testExport)
+ {
+ bluemonkey.log(prop +"="+ testExport[prop]);
+ }
+
+ var exported = dbus.exportObject("/one", "org.awesome.interface", dbus.Session, exportObj);
+ bluemonkey.log("exported: " + exported)
+
+ bluemonkey.assertIsTrue(exported, "Failed to export custom dbus object: " + dbus.errorMessage(dbus.Session));
+
+ var exported2 = dbus.exportObject("/two", "org.awesome.interface2", dbus.Session, testExport)
+ bluemonkey.log("exported2: " + exported2)
+
+ bluemonkey.assertIsTrue(exported2, "failed to export testExport: " + dbus.errorMessage());
+
+ //var exportedIface = dbus.createInterface("org.bluemonkey", "/", "org.awesome.interface", dbus.Session);
+
+ //bluemonkey.assertIsTrue(exportedIface.foo, "member 'foo' is missing " + dbus.errorMessage());
- var reply = dbusIface.GetId();
+ //var reply = exportedIface.foo();
- bluemonkey.log("org.freedesktop.DBus.GetId() response: " + reply);
+ //bluemonkey.assertIsTrue(reply === "bar" && exportedIface.bar === true);
+ }
+ catch(error)
+ {
+ bluemonkey.log("nasty dbus errors");
+ }
}
amb.createCustomProperty("VehicleSpeed", 10);