Wader DBus overview
Wader is started automatically the first time you invoke the Wader service:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader / es.warp.Wader.AddDevice \ string:/org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE method return sender=:1.47 -> dest=:1.48 reply_serial=2 object path "/org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE"
The argument that AddDevice
recibes is the root udi of the device that we are adding, in this case a
Huawei E620. The AddDevice
method should always be followed by
a es.warp.Wader.Card.Enable
operation on that device:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE \ es.warp.Wader.Card.Enable Error es.warp.Wader.Error.PIN: CMEErrorSIMPINRequired: es.warp.Wader.Error.PIN: es.warp.Wader.Error.PIN:
The Enable
method performs some initial setup on the device
and will return inmediatly if the device has no auth enabled, or has been
previously auth'ed. If the device needs some kind of auth, it will raise an
exception with what's needed. Once auth is complete, there's no need to
execute the Enable
method again. After a successful auth, the
device is given about fifteen seconds to settle and perform its internal
setup.
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE \ es.warp.Wader.PIN.Send string:0000 method return sender=:1.47 -> dest=:1.50 reply_serial=2 string "OK"
Had the device been already auth'ed, the previous shell commands could be comprised to just:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader / es.warp.Wader.AddDevice \ string:/org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE method return sender=:1.52 -> dest=:1.51 reply_serial=2 object path "/org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE" $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE \ es.warp.Wader.Card.Enable method return sender=:1.52 -> dest=:1.53 reply_serial=2
After this point you can interact with the device as you please.
And how do you obtain the UDIs of the devices then?
Wader internally interacts with hal
and requests the UDIs of
all the devices that have modem capabilities. As this is the UDI of the
device's child that has modem capabilities, we need to go up the
hal
tree until we find the "root" udi of that device, i.e.
the last node which still has the product and vendor tuple properties that
the node hal
reported as modem-capable. Why all this hassle?,
you might ask, instead of directly using
FindDeviceByCapability("modem")
results? The reasoning behind
this is because most devices register a data port and a control port. We are
not only interested on dialing
Wader will emit a DeviceAdded
signal when a new 3G device has
been added, and a DeviceRemoved
signal when a 3G device has
been removed.
The method es.warp.Wader.GetDevices
returns an array of object
paths, one for each device found in the system.
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader / es.warp.Wader.GetDevices method return sender=:1.156 -> dest=:1.155 reply_serial=2 array [ object path "/org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial" object path "/org/freedesktop/Hal/devices/pci_1931_c" object path "/org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial_0" ]This is the response of
GetDevices
with a Huawei E172, a E870 and
a Option GlobeTrotter 3G+ (Nozomi). Wader is able to detect, configure and use
the three at the same time with no interference between them whatsoever:
# this small for loop will Add and Enable the three devices $ ARRAY=(/org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ /org/freedesktop/Hal/devices/pci_1931_c \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial_0) $ ELEMENTS=${#ARRAY[@]} $ for ((i=0;i<$ELEMENTS;i++)); do dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ / es.warp.Wader.AddDevice string:${ARRAY[${i}]}; dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ ${ARRAY[${i}]} es.warp.Wader.Card.Enable; done # devices are added and enabled right now $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial_0 es.warp.Wader.Card.GetModel method return sender=:1.166 -> dest=:1.173 reply_serial=2 string "E272" $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial es.warp.Wader.Card.GetModel method return sender=:1.166 -> dest=:1.174 reply_serial=2 string "E17X" $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/pci_1931_c es.warp.Wader.Card.GetModel method return sender=:1.166 -> dest=:1.175 reply_serial=2 string "GlobeTrotter 3G+" # after getting the models, lets get the signal level $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial es.warp.Wader.Network.GetSignal method return sender=:1.166 -> dest=:1.179 reply_serial=2 int32 26 $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial_0 es.warp.Wader.Network.GetSignal method return sender=:1.166 -> dest=:1.178 reply_serial=2 int32 24 $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/pci_1931_c es.warp.Wader.Network.GetSignal method return sender=:1.166 -> dest=:1.177 reply_serial=2 int32 25
Operations you might want to do on a device
Once your device is set up, you will probably want to register with a given operator, or perhaps letting Wader to choose itself? Perhaps you want to do a high-level operation such as configuring the band and connection mode? We are going to provide examples for every one of them:
Registering to a network
Registering to a network will not be necessary most of the time as the devices themselves will register to its home network. Manually specifying a MNC to connect to an arbitrary network is, of course, possible:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE \ es.warp.Wader.Network.RegisterWithNetID int32:21401 method return sender=:1.47 -> dest=:1.51 reply_serial=2
The MNC 21401
is Vodafone Spain my current network provider.
If I try to connect to Telefonica's MNC 21407
, the operation will
probably fail horribly:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1001_HUAWEI_DEVICE \ es.warp.Wader.Network.RegisterWithNetID int32:21407 method return sender=:1.47 -> dest=:1.52 reply_serial=2
Oops, it didn't fail :). Although if I try to connect to Internet it will fail for sure as the APN is completely different.
Configuring connection settings
You might be interested on changing the connection mode from 2G to 3G. Or
perhaps you are interested on changing from GSM1900 to GSM850 if you are
roaming. Whatever your needs are, you are looking for the ConfigureConnection
method. ConfigureConnection
accepts a dictionary with one or
two keys:
band
: An unsigned int specifies the wanted band according to the following dictionary/enum:BAND_OPTS = { 0 : 'EGSM', # EGSM (900MHz) 1 : 'DCS', # DCS (1800MHz) 2 : 'PCS', # PCS (1900MHz) 3 : 'G850', # GSM (850MHz) 4 : 'U2100', # WCDMA 2100MHz (Class I) 5 : 'U1700', # WCDMA 3GPP UMTS1800 (Class III) 6 : 'U17IV', # WCDMA 3GPP AWS 1700/2100 (Class IV) 7 : 'U850', # WCDMA 3GPP UMTS850 (Class V) 8 : 'U800', # WCDMA 3GPP UMTS800 (Class VI) 9 : 'U900', # WCDMA 3GPP UMTS900 (Class VIII) 10 : 'U17IX', # WCDMA 3GPP UMTS (Class IX) 11 : 'ANY', # ANY }
conn
: An unsigned int specifies the desired connection mode according to the following dictionary/enum:CONN_OPTS = { 0 : '2GONLY', # 2G Only 1 : '3GONLY', # 3G Only 2 : '2GPREF', # 2G preferred 3 : '3GPREF', # 3G preferred 4 : 'ANY', # Any connection mode }
dbus-send
does not support a syntax for specifying
dictionaries, we will use a python script to illustrate its usage:
# -*- coding: utf-8 -*- # Copyright (C) 2008 Warp Networks S.L. # Author: Pablo Martí """ Example DBus client I will configure a connection with some preferences. I obtain the device udi as the only argument to the script i.e. $ ./client2.py /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial """ import sys import traceback import gobject import dbus import dbus.mainloop.glib from wader.common.consts import (WADER_SERVICE, WADER_OBJPATH, WADER_INTFACE, CRD_INTFACE) from wader.common.hardware import CONN_OPTS_REV, BAND_OPTS_REV def handle_response(resp=None): """ Callback for methods that emit output or not """ if resp: print "Response", resp else: print "No response" def handle_error(resp): """ Handles any error occurred """ print "ERROR", resp def remove_device(): """ Removes the device specified by C{sys.argv[1]} """ print "Removing device after configuring it" remote_object.RemoveDevice(sys.argv[1], dbus_interface=WADER_INTFACE, reply_handler=handle_response, error_handler=handle_error) return True def obtain_device(): """ Obtains the device specified by C{sys.argv[1]} """ remote_object.AddDevice(sys.argv[1], dbus_interface=WADER_INTFACE, reply_handler=handle_get_device, error_handler=handle_error) return False def handle_get_device(opath): """ Obtains a reference to C{opath} and starts device operations """ # now we've obtained a proxy to the object device_object = bus.get_object(WADER_SERVICE, opath) # Enable it device_object.Enable(dbus_interface=CRD_INTFACE, reply_handler=handle_response, error_handler=handle_error) # in 1.5seconds configure the connection gobject.timeout_add(1500, configure_conn, device_object) def configure_conn(device_object): """ Configures the connection in C{device_object} """ # we want 3GONLY and a WCDMA2100 band conf = dict(conn=CONN_OPTS_REV['3GONLY'], band=BAND_OPTS_REV['U2100']) #conf = dict(conn=1, band=4) # issue the ConfigureConnection command device_object.ConfigureConnection(conf, dbus_interface=CRD_INTFACE, reply_handler=handle_configure_conn, error_handler=handle_error) def handle_configure_conn(response=None): handle_response(response) gobject.timeout_add(3000, remove_device) return False if __name__ == '__main__': if not len(sys.argv): raise SystemExit("You must specify a device root udi") dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = dbus.SessionBus() try: # get a reference to the main WADER object remote_object = bus.get_object(WADER_SERVICE, WADER_OBJPATH) except dbus.DBusException: traceback.print_exc() sys.exit(1) # Start the chained calls in 1s gobject.timeout_add(1000, obtain_device) loop = gobject.MainLoop() loop.run()
- Call
AddDevice
with the root udi of the device to use. This is received as the only argument to the script. This in turn executes thehandle_get_device
method. handle_get_device
in turn obtains a reference to the device, executes theEnable
operation and schedules a call to theconfigure_conn
method with the object path of the device as argument.configure_conn
builds a dictionary with the values we are interested in (3g only as connection mode and a WCDMA2100 band) and executes theConfigureConnection
method with the dictionary as argument.
Sending a SMS
Sending a SMS can not be any easier:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ es.warp.Wader.SMS.Send string:+34606575119 string:"hey dude" method return sender sender=:1.65 -> dest=:1.67 reply_serial=2 uint32 21And sending an UCS2 encoded SMS can't get any easier either:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ es.warp.Wader.SMS.Send string:+34606575119 string:中兴通讯 method return sender=:1.65 -> dest=:1.68 reply_serial=2 uint32 22
Adding/Reading a Contact
Adding a contact to the SIM and getting the index where it was stored:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ es.warp.Wader.Contacts.Add string:Pablo string:+34545665655 method return sender=:1.54 -> dest=:1.57 reply_serial=2 uint32 1And reading it again:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ es.warp.Wader.Contacts.GetByIndex uint32:1 method return sender=:1.54 -> dest=:1.58 reply_serial=2 struct { uint32 1 string "Pablo" string "+34545665655" }Now lets add another contact and read all the contacts in the SIM card:
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ es.warp.Wader.Contacts.Add string:John string:+33546657784 method return sender=:1.54 -> dest=:1.60 reply_serial=2 uint32 2 $ dbus-send --type=method_call --print-reply --dest=es.warp.Wader \ /org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial \ es.warp.Wader.Contacts.List method return sender=:1.54 -> dest=:1.61 reply_serial=2 array [ struct { uint32 1 string "Pablo" string "+34545665655" } struct { uint32 2 string "John" string "+33546657784" } ]
Troubleshooting
"Launch helper exited with unknown return code 0"
$ dbus-send --type=method_call --print-reply --dest=es.warp.Wader / es.warp.Wader.AddDevice \ string:/org/freedesktop/Hal/devices/usb_device_12d1_1003_noserial Error org.freedesktop.DBus.Error.Spawn.ChildExited: Launch helper exited with unknown return code 0
If the operation es.warp.Wader.AddDevice
returns with the above
error message, you will have to repeat the operation one more time and it will
succeed this one. We do not have a workaround for this yet.
Operation X failed on my device
Every device its a world on its own, sometimes they are shipped with a buggy firmware, sometimes a device will reply to a command on a slightly different way that will break the parsing of the reply.
Wader ships with a test suite that might yield some clues about what went wrong. Instructions to execute it:
cp /usr/share/wader/resources/test/settings.conf /tmp trial -r gtk2 wader.testWe need to copy that file to
/tmp
first because as we are going
to fiddle with the PIN, SMSC and other potential dangerous settings, we need
a place where the "good" ones are stored.
Do not forget to edit the file according to your settings! Also do not forget
the -r gtk2
switch, it will pick the
gtk2 reactor to run the tests, otherwise all the glib-dependent tests, like
the DBus ones would fail.