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.
[…] 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 […]
[…] 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 […]
Nice article,keep up good work.
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.
Hi Joshua!
Glad to here it still helps people!!!
As you recognized, it’s a very old posting and I don’t work with ofono anymore. But you remind me to start blogging about my current activities 🙂
Maybe some code examples could be helpful for you as well. Have a look at:
https://github.com/matgnt/mobos-gui
And the demos on youtube:
https://www.youtube.com/user/matgnt
Good luck with your project!
Matthias