In Gambas, a method - declared as a function - can return exactly one value. A D-Bus signal or method, on the other hand, can return multiple values. Via the signature of a signal or a method, you can easily see how many values are returned with a received signal or with a method call via their arguments - stored in a Variant array - and which data type the individual D-Bus values have.
The classes DBusVariant and DBusValues (gb.dbus) allow you to define D-Bus values to a given D-Bus signature. You can read the description of the two classes DBusVariant and DBusValues in chapter 24.9.8.0. Both classes have only the property Value and one constant each. There you will also learn that you must use the class DBusVariant for a signature such as “(ia{sv}av)” and the class DBusValues for a signature such as “u(ia{sv}av)”.
Note:
See http://gambaswiki.org/wiki/doc/dbus#t10 for a table summarising how Gambas data types are converted to D-Bus data types and vice versa.
Definition: A D-Bus signature is defined as a string constant.
To evaluate the return value of a D-Bus method or an intercepted D-Bus signal you need their signatures to map the D-Bus data with its D-Bus data types to Gambas data and its data types.
In example 1, a special signal “MountAdded” is analysed, which is sent by the d-bus-enabled application with the D-bus name org.gtk.vfs.UDisks2VolumeMonitor and with the object path /org/gtk/Private/RemoteVolumeMonitor - among many other signals - when, for example, a USB stick is plugged in. You can use the console programme dbus-send for introspection:
$ dbus-send --session --print-reply --dest=org.gtk.vfs.UDisks2VolumeMonitor \ /org/gtk/Private/RemoteVolumeMonitor \ org.freedesktop.DBus.Introspectable.Introspect > volumemonitor.introspection.xml
Here is an excerpt from the XML file volumemonitor.introspection.xml:
<signal name="MountAdded"> <arg type="s" name="dbus_name"/> <arg type="s" name="id"/> <arg type="(ssssssbsassa{sv})" name="mount"/> </signal>
You need the specified signatures to map the D-Bus data with its D-Bus data types to Gambas data and its data types. According to the conversion table above, you can see that the first two arguments have the native data type “s”, which Gambas also knows. Therefore you do not have to convert anything here. The situation is completely different for the third argument with the signature “ssssssbsassa{sv}”, which can be characterised as a complex data type:
String String String String String String Boolean String String-Array String Collection(String:Variant)
These are the individual Gambas data types that can be specified for the third argument according to the table above, where the third argument is a variant array by type - recognisable by the enclosing round brackets in the signature. The round brackets are also noted in the D-Bus notation as Struct of (…). Array of [datatype] indicates an array with elements of the specified data type. For example, the D-Bus notation Dict of {…} stands for a{ss} or a{sv} and requires conversion to the Gambas data type Collection.
Struct of ( s 6x String b 1x Boolean s 1x String Array of [string] 1x String-Array s 1x String Dict of {String,Variant} 1x Collection (Key-Typ=String, Value-Typ=Variant) )
If you intercept the signal via the class DBusObserver with the message type 'DBus.Signal' and the event hDbusObserver_Message(), then this declaration of suitable variables and the subsequent value assignments (variable ⇒ argument value) are suitable:
Public Sub hDBusObserver_Message() Dim bTF as Boolean Dim k as Integer = 1 Dim sA1, sA2 As String Dim sA31, sA32, sA33, sA34, sA35, sA36, sA37, sA38 As String Dim vElement As Variant Dim cCollection As Collection Dim aArray As String[] Dim aSignalArguments As Variant[] aSignalArguments = hDBusObserver.Message.Arguments ' Speichern aller Signal-Argumente in aSignalArguments sA1 = aSignalArguments[0] sA2 = aSignalArguments[1] sA31 = aSignalArguments[2][0] sA32 = aSignalArguments[2][1] sA33 = aSignalArguments[2][2] sA34 = aSignalArguments[2][3] sA35 = aSignalArguments[2][4] sA36 = aSignalArguments[2][5] bTF = aSignalArguments[2][6] sA37 = aSignalArguments[2][7] aArray = New String[] aArray = aSignalArguments[2][8] If aArray.Count > 0 Then For Each vElement In Array Print "Element " & Str(k) & " = " & vElement Inc k Next Else Print "Attention: The string array is empty!" & gb.NewLine Endif sA38 = aSignalArguments[2][9] ' Collection -> KeyType = String, DataType = Variant cCollection = New Collection cCollection = aSignalArguments[2][10] If cCollection.Count > 0 Then For Each vElement In cCollection Print "Element " & Str(k) & " : " & cCollection.Key & " = " & vElement & gb.NewLine Inc k Next Else Print "Attention: The collection is empty!" Endif End
For this example, you will be introduced to a D-Bus data server and a D-Bus client. The server provides a service where a method call (GetT(…)) with a (string) argument returns a value with a complex data type.
Figure 24.9.0.3.1: The service is used …
For demonstration purposes, the second example is deliberately constructed so that the signature of the return value of the GetT(…) method uses many data types.
String s0 ' Sensor Number/Type: 70358 KNX T-B-UP Integer 1 i1 ' Day 15 Integer 2 i2 ' Month 12 Integer 3 i3 ' Year 2017 Variant-Array av Array[0] i4 ' Hour 15 Array[1] i5 ' Minute 24 Array[2] i6 ' Second 37 Array[3] s1 ' Time zone "LocalTime" Collection a{sv} ' Key.Type=String, Value-Type=Variant c["T"] f1 ' Temperature -1.4 c["L"] s2 ' Label ° c["S"] s3 ' Scale C Boolean b0 ' TempLog True/False
With these specifications for the return value of the method GetT(…), the following signature results after a conversion of the Gambas data types into D-Bus data types, which is described in a separate file - here RValue.class - as a string constant:
' Gambas class file Export Inherits DBusValues Public Const Signature As String = "siiiava{sv}b" Eine Introspection für das exportierte Objekt liefert diese Übersicht: <interface name="org.gambas.dbusserver3.msservice"> <method name="GetT"> <arg name="arg1" type="s"/> <arg name="value1" type="s" direction="out"/> <arg name="value2" type="i" direction="out"/> <arg name="value3" type="i" direction="out"/> <arg name="value4" type="i" direction="out"/> <arg name="value5" type="av" direction="out"/> <arg name="value6" type="a{sv}" direction="out"/> <arg name="value7" type="b" direction="out"/> </method> </interface>
In a further step, after declaring the signature, you must define the method GetT(…) in another class file (MSService.class). The data type of the function value is of type RValue:
' Gambas class file Inherits DBusObject Create Static ' Signal definition ... '' Definition of a method. The method has exactly one argument. Public Function GetT(ShortScale As String) As RValue Dim hItem As RValue Dim s0, s1, s2, s3 As String Dim i1, i2, i3, i4, i5, i6 As Integer Dim f1 As Float Dim aTime As Variant[] Dim cTemperature As Collection Dim bTempLog As Boolean s0 = "Sensor 34 : 70358 KNX T-B-UP" i1 = Day(Now()) i2 = Month(Now()) i3 = Year(Now()) i4 = Hour(Now()) i5 = Minute(Now()) i6 = Second(Now()) s1 = ("LocalTime") aTime = [i4, i5, i6, s1] ' The temperature value is read out in real operation from an RS232-AD converter ' A random value for the current temperature is generated here f1 = Round(Rnd(-3, 2), -4) Select Case ShortScale Case "C" s2 = "°" s3 = "C" Case "K" f1 = f1 + 273.15 s2 = "" s3 = "K" Case "F" f1 = (9 / 5) * f1 + 32 s2 = "°" s3 = "F" Default s2 = "°" s3 = "C" End Select cTemperature = New Collection cTemperature.Add(f1, "Temperature") ' Temperature cTemperature.Add(s2, "Label") ' Label cTemperature.Add(s3, "Scale") ' Temperature scale bTempLog = True hItem = New RValue ' hItem.Value with complex data type: hItem.Value = [s0, i1, i2, i3, aTime, cTemperature, bTempLog] Return hItem End
In the download area you will find the projects for the D-Bus Server3 and the D-Bus Client3 so that you can understand the interaction of D-Bus signature and data conversion yourself.
The client not only reads the complex return value with the signature “siiiava{sv}b”, but also evaluates a signal that the server sends when it is switched on or off. For the client, an introspection of the server service was also implemented.