Qt, Ofono, D-Bus and QML – Part 2

Since we have already a running Ofono with an activated modem (see part 1), we can continue with creating Proxy-Classes for Qt.

Gather API-Information

A D-Bus-API usually gives you the opportunity to get API information through a function called Introspect. We do so with dbus-send:


dbus-send --print-reply --system --dest=org.ofono /phonesim org.freedesktop.DBus.Introspectable.Introspect > ofono.xml

To get all the necessary information, the command must be executed after the modem has been activated (see part 1). The produced file ofono.xml is not yet a valid XML document. You have to remove a few debug lines at the beginning and at the enf of the file to make it valid.

Create Proxy-Classes

Qt comes with a nice tool the automatically create Proxy-Classes out of the XML description of a D-Bus-API. It’s called qdbusxml2cpp. With this tool you can create proxy and adaptor classes. The latter is used to get your own Qt methods published on the D-Bus, but here we want to use existing D-Bus methods, so we use Proxy-Classes.


qdbusxml2cpp -p OfonoModem ofono.xml org.ofono.Modem
qdbusxml2cpp -p OfonoSimManager ofono.xml org.ofono.SimManager
qdbusxml2cpp -p OfonoVoiceCallManager ofono.xml org.ofono.VoiceCallManager

You see, the command has to be executed three times to separate the D-Bus-Interfaces. The parameter -p says that a proxy (not an adaptor) class shall be created, while the last parameter limits the output to only the specified Interface. The above parameters are for the Qt 4.6 version of  qdbusxml2cpp. I saw the 4.7 version uses slightly different parameters.

But wait a second. You will probably get erros while executing the above commands because of an unrecognized type. That means you have to teach qdbusxml2cpp or Qt how to handle some special types. That’s done by annotations in the xml file:


<method name="GetProperties">
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg type="a{sv}" direction="out"/>
 </method>

The Listing shows how the unrecognized type (“a{sv}”) can be represented in Qt. The annotation is on the same level as the unrecognized type. After your XML file is adapted, the above qdbusxml2cpp commands will work.

Use Proxy-Classes

To get rid of the dbus-send command to activate the modem we want to do this in C++:


void Ofono::setPowerOn() {
    OrgOfonoModemInterface ofono("org.ofono", "/phonesim", QDBusConnection::systemBus());
    ofono.SetProperty("Powered", QDBusVariant(true));
}

That’s it. The class OrgOfonoModemInterface has been created by qdbusxml2cpp. But it can be a bit more complex, e.g. to convert a incoming PropertyChange-Signal.


Ofono::Ofono(QObject *parent) :
    QObject(parent)
{
    m_VoiceCallManager = new OrgOfonoVoiceCallManagerInterface("org.ofono", "/phonesim", QDBusConnection::systemBus());
    // DBus signals
    connect(m_VoiceCallManager, SIGNAL(PropertyChanged(const QString, const QDBusVariant)), this, SLOT(PropertyChanged(const QString, const QDBusVariant)));
}

The Listing shows how a OrgOfonoVoiceCallManagerInterface instance is created to connect the necessary PropertyChanged-Signal to our Slot with the same name, which might look like the following:

void Ofono::PropertyChanged(const QString &name, const QDBusVariant &value)
{
    qDebug() << name;
    if(name == "Calls") {

        const QVariant var = value.variant();
        const QDBusArgument a = var.value<QDBusArgument>();

        a.beginArray();
        while(!a.atEnd()) {
            QDBusObjectPath opath;
            a >> opath;
            // debug output or do something else
            qDebug() << opath;
            emit callChanged(opath.path());
        }
        a.endArray();
    }
}

You can have a look into the above created ofono.xml file where you can see, the PropertyChanged-Signal comes with a String and a Variant. Therefore qdbusxml2cpp has automatically translated into a QDbusVairant. But a Variant can be a lot of differnt types indeed. How to get this information to convert it to an appropriate Qt-Type?

First of all, you could have a look into the Ofono project documentation which is quite good. But for other projects the documentation might not be as good as Ofono’s. How to get the information then? Well, let’s use dbus-monitor:


dbus-monitor --system sender=org.ofono
...
signal sender=:1.78 -> dest=(null destination) serial=52 path=/phonesim; interface=org.ofono.VoiceCallManager; member=PropertyChanged
 string "Calls"
 variant       array [
 object path "/phonesim/voicecall01"
 ]

With dbus-monitor you can exactly see what’s inside the Variant. With this information and the Qt documentation on how D-Bus-Types are mapped into Qt-Types, you can create the above PropertyChanged-Slot.

Ok I see, it’s a third part necessary to explain how to use all this things in QML.

5 Responses to Qt, Ofono, D-Bus and QML – Part 2

  1. […] dbus-send you can execute further methods on the Ofono-D-Bus-API. In part 2 I’ll describe how to connect to the API from within […]

  2. […] Ofono, D-Bus and QML – Part 3 In the last part we’ve created a connection to D-Bus from within Qt-C++ to execute methods to e.g. activate […]

  3. Proxy List says:

    Nice article,keep up good work.

  4. Joshua says:

    Very nice work. This is actually the first info I could get for using ofono from within c++. I see this post is kinda old , I hope you see this. You made my day. If possible post using ofono for accessing sms features within c++. Thanks.

Leave a reply to Joshua Cancel reply