Embedded Linux Qt DBus with Custom Types 2

Embedded Linux Qt DBus with Custom Types 2


I wrote another DBus article awhile back. I'll keep that one around for now but hope that this step by step tutorial is a bit easier. Feedback is always appreciated!

To use Dbus with custom types, perform the following steps.

1.) First create a Qt regular class using the QOBJECT Macro and create some methods

you would like to be able to call over dbus. My class was named DbusReceiverTemplate.

The method I want to call over dbus is setSetting. In the header files, ensure

you add the Macros shown - Q_CLASSINFO is necessary to define the interface name. And

in the Implementation file, ensure you include the ifadaptor class ( created in step 2 )

and in the constructor make the appropriate dbus registration calls as shown below.

HEADER:

#ifndef DBUSRECEIVERTEMPLATE_H

#define DBUSRECEIVERTEMPLATE_H


#include <QObject>

#include <QVariant>

#include "global.h"


// Custom Dbus Types

#include "dbuscustomtype.h"


class DbusReceiverTemplate : QObject

{


Q_OBJECT

Q_CLASSINFO("D-Bus Interface", "com.company.proj.simple.command") // Define the interface name


public:


DbusReceiverTemplate(); // Constructor


public slots:


// Set a camera mode setting

int setSetting( const DbusCustomType &setting );


};


#endif // DBUSRECEIVERTEMPLATE_H


IMPLEMENTATION:

#include "dbusreceivertemplate.h"

#include "dbusifadapter.h"

#include <QDebug>


// Custom Dbus Types

#include "dbuscustomtype.h"


/// NOTE: To recreate the ifadaptor after adding new methods here, do the following:

/// 1.) qdbuscpp2xml -M dbusreceivertemplate.h -o com.company.proj.simple.command.xml

/// 2.) qdbusxml2cpp -v -c dbusifadapter -a dbusifadapter.h:dbusifadaptor.cpp com.company.proj.simple.command.xml


// Constructor

DbusReceiverTemplate::DbusReceiverTemplate() {


new dbusifadapter(this); // Cleans itself up

QDBusConnection dbus = QDBusConnection::sessionBus(); // Use session bus

dbus.registerObject("/",this); // Register object on the bus

dbus.registerService("com.company.proj.simple.command"); // Expose interface to others


}


// This method is used from this template by the Qt Dbus

// conversion tools to create a callable Dbus method to

// set the camera settings using a QVariant

//

int DbusReceiverTemplate::setSetting( const DbusCustomType &setting ) {


// Do stuff here that will happen when this method is called

// from another process through dbus


}


2.) Now use the qdbuscpp2xml tool to create a dbus specific interface description xml

file and then the qdbusxml2cpp tool to create an interface adaptor class from that xml

file by running the following commands:


>> qdbuscpp2xml -M dbusreceivertemplate.h -o com.company.proj.simple.command.xml

>> qdbusxml2cpp -v -c dbusifadapter -a dbusifadapter.h:dbusifadaptor.cpp com.company.proj.simple.command.xml


3.) Now create a class ( here, DbusCustomType ) that will define the custom class to be sent

across dbus. Mine looks like below. Make sure you register the custom type with the meta

object system in Qt using the "Q_DECLARE_METATYPE(DbusCustomType);" code at the bottom of

the header file. Notice how the streaming operators must be overridden for this custom type.


HEADER:

#ifndef DBUSCUSTOMTYPE_H

#define DBUSCUSTOMTYPE_H


#include <QMetaType>

#include <QDBusMetaType>

#include "QDebug"


/**

* @brief

* Implements a type that can be used by the meta-object system. Including Q_PROPERTY, QVariant, and

* in signals/slots. You need to add this line (preferrably in main) before any signal/slot connections

* are made: qRegisterMetaType<DbusCustomType>();

*/

class DbusCustomType

{

public:


DbusCustomType();


// Settings - name / value / type

QString m_Value;

QString m_SettingName;

QString m_Type;


// Override << and >> for Dbus communication of this type

friend QDBusArgument &operator<<(QDBusArgument &argument, const DbusCustomType &setting);

friend const QDBusArgument &operator>>(const QDBusArgument &argument, DbusCustomType &setting);


};


Q_DECLARE_METATYPE(DbusCustomType);


#endif // DBUSCUSTOMTYPE_H


IMPLEMENTATION:

#include "dbuscustomtype.h"


DbusCustomType::DbusCustomType()

{

}


// Marshall the Data data into a D-Bus argument

QDBusArgument &operator<<(QDBusArgument &argument, const DbusCustomType &setting)

{


argument.beginStructure();

argument << setting.m_Value;

argument << setting.m_SettingName;

argument << setting.m_Type;

argument.endStructure();

return argument;


}


// Retrieve the Data data from the D-Bus argument

const QDBusArgument &operator>>(const QDBusArgument &argument, DbusCustomType &setting)

{


argument.beginStructure();

argument >> setting.m_Value;

argument >> setting.m_SettingName;

argument >> setting.m_Type;

argument.endStructure();

return argument;


}


4.) Finally, make sure you register the custom type with qdbus and the meta object type system in Qt

before using dbus to communicate with an instance of the custom type. I did this by adding the following

code to main():


// Register custom Dbus Types

qRegisterMetaType<DbusCustomType>("DbusCustomType");

qDBusRegisterMetaType<DbusCustomType>();


5.) That's it for the dbus server ( receiver-side ) App. Now for the sender App. Create a new project and

copy the dbuscustomtype header and implementation files from the receiver app to the sender app. Also, register

the custom type with the Meta Type system in main with the following code:


// Register custom Dbus Types

qRegisterMetaType<DbusCustomType>("DbusCustomType");

qDBusRegisterMetaType<DbusCustomType>();


6.) Create a SendDbusCustomType class that looks like the following. Note the inline definitions for the

methods we want to be able to call over Dbus.


HEADER:

#ifndef SENDDBUSCUSTOMTYPE_H

#define SENDDBUSCUSTOMTYPE_H


#include <QtCore/QObject>

#include <QtCore/QByteArray>

#include <QtCore/QList>

#include <QtCore/QMap>

#include <QtCore/QString>

#include <QtCore/QStringList>

#include <QtCore/QVariant>

#include <QtDBus/QtDBus>


// For the custom class transmission

#include "dbuscustomtype.h"

#include "span.h"


/*

* Proxy class for interface com.company.proj.simple.command

*/

class SendDbusCustomType: public QDBusAbstractInterface

{

Q_OBJECT


public:


static inline const char *staticInterfaceName() {

return "com.company.proj.simple.command";

}


public:


SendDbusCustomType(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);


~SendDbusCustomType();


public Q_SLOTS: // METHODS


// It looks like:

// int sendDbusCustomType::setMode(const int cmd)

inline QDBusPendingReply<int> setMode(const int cmd)

{


QList<QVariant> argumentList;

argumentList << QVariant::fromValue(cmd);

return asyncCallWithArgumentList(QLatin1String("setMode"), argumentList);


}


// It looks like:

// int sendDbusCustomType::setSetting(const QDBusVariant setting)

inline QDBusPendingReply<int> setSetting(const DbusCustomType setting)

{


QList<QVariant> argumentList;

argumentList << QVariant::fromValue(setting);

return asyncCallWithArgumentList(QLatin1String("setSetting"), argumentList);


}


Q_SIGNALS: // SIGNALS

};


namespace com {

namespace company {

namespace proj {

namespace camera {

typedef ::SendDbusCustomType command;

}

}

}

}


#endif // SENDDBUSCUSTOMTYPE_H


IMPLEMENTATION:

#include "senddbuscustomtype.h"


/*

* Implementation of interface class dbussender

*/


SendDbusCustomType::SendDbusCustomType(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)

{

}


SendDbusCustomType::~SendDbusCustomType()

{

}


7.) Now in main(), call the methods like so:


SendDbusCustomType* client = new SendDbusCustomType("com.company.proj.command.gui", "/", QDBusConnection::sessionBus(), 0);


// Check return status of dbus call

int response;


qDebug() << "Sending Camera Mode ( int ) to GUI...";

DbusCustomType setting;

setting.m_SettingName = "cameraMode";

setting.m_Value = "1";

setting.m_Type = "int";

response = client->setSetting(setting);

qDebug() << "RESPONSE: " << response;

That concludes the simple example to send a custom type over Dbus! Happy Coding.




ClassyBits 2016