User Tools

Site Tools


Sidebar

Network and communication

k24:k24.9:k24.9.8:k24.9.8.2:start

24.9.8.2 Projects - Create, Export and Use D-Bus Object

In this chapter you will be introduced to, among other things, a Gambas program that implements a D-Bus server that provides a service to d-bus enabled programs that a D-Bus object exported to the session D-Bus provides. The implemented service can be described like this:

  • If the implemented method GetT(ShortScale As String) is called with a parameter of data type String by a d-bus capable client, then a return value with a complex data type is returned.
  • The complex data type - described in the signature “(siiiava{sv})” - was chosen to cover a wide range of applications for your own projects.

The complex data type for the return value of the method GetT(ShortScale As String) has the signature “(siiiava{sv})”. This signature becomes understandable if you look at the (partial) data of the return value with their 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

Since the function value for GetT(ShortScale As String) is not a native data type, you have to take care of converting the individual Gambas data types into D-Bus data types! Use the table at http://gambaswiki.org/wiki/doc/dbus#t10 to learn how Gambas data types are converted to D-Bus data types and vice versa.

Signatures have already been described in chapters 24.9.0.3 and 24.9.6.3.

24.9.8.2.1 Project Server

The source code for the D-Bus server consists, in the case of a complex data type for the return value of the implemented method, of at least 3 class files whose names you can freely define:

  • (A) In the file RValue.class, the complex data type for the return value of the method GetT(…) is defined via its signature constant.
  • (B) The service is implemented in a D-Bus object described in a special class file MSService.class. The class uses the return value of the GetT(…) method from (A).
  • (C) In the start class FMain.class, the D-bus object “/MSService” from (B) is exported to the session D-bus so that d-bus capable programs can use the service.

First create a new class RValue.class to be exported (Export) and from the class DBusVariant (Inherits DBusVariant). Then define the required signature as a constant. The relevant source code of the class RValue.class in the first 6 lines is very short. All further lines are a description of the signature.

' Gambas class file
 
Export
Inherits DBusVariant
 
Public Const Signature As String = "(siiiava{sv})"
 
' Signature = "(siiiava{sv})"
'--------------------------------------------------------------
' 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
 
' The introspection shows the signature of the method and the type of the one argument
 
' 1. Case with the command 'dbus-send' in one console:
' dbus-send --session --print-reply --dest=org.gambas.dbusserver2 \
' /MSService org.freedesktop.DBus.Introspectable.Introspect \
' > tservice.introspection.xml
 
' 2. Case with code for introspection in DBusClient2:
' sXMLDocument = DBus[("session://" & "org.gambas.dbusserver2")]._Introspect("/MSService")
' Extract from the XML document:
'  ...
'   <interface name="org.gambas.dbusserver2.msservice">
'     <method name="GetT">
'       <arg name="arg1" type="s"/>
'       <arg name="value" type="(siiiava{sv})" direction="out"/>
'     </method>
'   </interface>
'  ...

Then declare a method GetT(…) in the file MSService.class, whose function value is of type RValue. Proceed according to the following concept:

  1. First create a new object hItem of the data type RValue in the function GetT(ShortScale As String) As RValue (lines 14 and 59).
  2. Then assign the intended values to all (partial) data that exist in the return value (lines 21 to 30 as well as line 35).
  3. Then assign the array [s0, i1, i2, i3, aTime, cTemperature] to the property hItem.Value, which follows the above signature “(siiiava{sv})”. Beforehand, fill the Variant array (line 31) with the appropriate values and the Collection with the planned value-key pairs (lines 55 to 57).
  4. Finally, return the object hItem with 'Return hItem' as the function value of GetT(…) (line 63).

The following source code in the MSService.class file implements the concept:

[1] ' Gambas class file
[2]
[3] Inherits DBusObject
[4] Create Static
[5]
[6] '' Definition of a signal:
[7] '' This signal has exactly 1 argument 'sFlag' of the data type string
[8] Event org_gambas_dbusserver2_MSService_OnOff(sFlag As String)
[9]
[10] '' Definition of a method:
[11] '' The method has exactly one argument.
[12] Public Function GetT(ShortScale As String) As RValue
[13]
[14]   Dim hItem As RValue
[15]   Dim s0, s1, s2, s3 As String
[16]   Dim i1, i2, i3, i4, i5, i6 As Integer
[17]   Dim f1 As Float
[18]   Dim aTime As Variant[]
[19]   Dim cTemperature As Collection
[20]
[21]   s0 = "Sensor 34 : 70358 KNX T-B-UP"
[22]
[23]   i1 = Day(Now())
[24]   i2 = Month(Now())
[25]   i3 = Year(Now())
[26]
[27]   i4 = Hour(Now())
[28]   i5 = Minute(Now())
[29]   i6 = Second(Now())
[30]   s1 = "LocalTime"
[31]   aTime = [i4, i5, i6, s1]
[32]
[33] ' The temperature value is read out in real operation from an RS232-AD converter
[34] ' A random value for the current temperature is generated here
[35]   f1 = Round(Rnd(-3, 2), -4)
[36]
[37]   Select Case ShortScale
[38]     Case "C"
[39]       s2 = "°"
[40]       s3 = "C"
[41]     Case "K"
[42]       f1 = f1 + 273.15
[43]       s2 = ""
[44]       s3 = "K"
[45]     Case "F"
[46]       f1 = (9 / 5) * f1 + 32
[47]       s2 = "°"
[48]       s3 = "F"
[49]     Default
[50]       s2 = "°"
[51]       s3 = "C"
[52]   End Select
[53]
[54]   cTemperature = New Collection
[55]   cTemperature.Add(f1, "Temperature") ' Temperature
[56]   cTemperature.Add(s2, "Label")       ' Label
[57]   cTemperature.Add(s3, "Scale")       ' Temperature scale
[58]
[59]   hItem = New RValue
[60] ' hItem.Value with complex data type:
[61]   hItem.Value = [s0, i1, i2, i3, aTime, cTemperature]
[62]
[63]   Return hItem
[64]
[65] End

Hint:

In line 8, a signal is declared with an argument. This signal is sent when the server is switched off or restarted. The client intercepts this signal and reacts according to the read value (“on” or “off”) of the argument.

In the source code of FMain.class, registering the D-Bus object in line 15 and sending a D-Bus signal in lines 22 and 41 are the central instructions after creating a new D-Bus object of type MSService in line 8:

[1] ' Gambas class file
[2]
[3] Private hDBusObject As MSService
[4] Private hDBusSignal As DBusSignal
[5]
[6] Public Sub Form_Open()
[7]
[8]   hDBusObject = New MSService
[9]
[10]   FMain.Resizable = False
[11]   FMain.Caption = ("The data server is activated")
[12]   DBus.Unique = True
[13] ' For tests only: DBus.Debug = True
[14]
[15]   Try DBus.Session.Register(hDBusObject, "/MSService")
[16]   If Error Then
[17]      Message.Error("An instance of " & Application.Name & " already exists.")
[18]      FMain.Close()
[19]   Endif
[20]
[21]   hDBusSignal = New DBusSignal(DBus.Session, Null, True)
[22]   SendSignal("on")
[23]
[24] End
[25]
[26] Private Sub SendSignal(OnOff As String)
[27]
[28]   Dim sSignalName As String
[29]   Dim aArguments As New Variant[]
[30]
[31]   sSignalName = "org.gambas.dbusserver2.MSService.OnOff"
[32]   aArguments = [OnOff]
[33]
[34]   DBus.Raise(hDBusObject, sSignalName, aArguments)
[35]
[36] End
[37]
[38] Public Sub Form_Close()
[39]
[40]   SendSignal("off")
[41]
[42]   If hDBusSignal Then hDBusSignal.Enabled = False
[43]   If DBus.IsRegistered(hDBusObject) Then DBus.Session.Unregister(hDBusObject)
[44]
[45]   FMain.Close()
[46]
[47] End
 
===== 24.9.8.2.2 Projekt Client =====
 
Der Quelltext für den Client dbusclient2 wird vollständig angegeben und anschließend kommentiert:
 
<code gambas>
[1] ' Gambas class file
[2]
[3] Private $hDBusProxy As DBusProxy
[4] Private $hDBusSignal As DBusSignal
[5]
[6] Private $sDBusName As String
[7] Private $sDBusObjectPath As String
[8] Private $sReportLine As String
[9] Private $hDate As Date
[10] Private $bInspectable As Boolean
[11] Private k As Integer
[12] Private $iFirst As Integer
[13]
[14] Public Sub Form_Open()
[15]
[16]   Dim sMessage As String
[17]
[18]   DBus.Debug = True
[19]   FMain.Resizable = False
[20]   FMain.Caption = ("Remote data enquiry via D-Bus")
[21]   Application.MainWindow = FMain
[22]
[23]   cmbScale.Add("Celsius")
[24]   cmbScale.Add("Kelvin")
[25]   cmbScale.Add("Fahrenheit")
[26]   cmbScale.Index = 0
[27]
[28]   $sDBusName = "org.gambas.dbusserver2"
[29]   $sDBusObjectPath = "/MSService"
[30]
[31] If Not DBus.Session.Applications.Exist($sDBusName) Then
[32]      sMessage = ("There is no suitable data server on the session bus!")
[33]      sMessage &= "<center><font color='red'>"
[34]      sMessage &= ("The program is terminated.")
[35]      sMessage &= "</font></center>"
[36]      Message.Warning(sMessage)
[37]      FMain.Close()
[38]   Else
[39]     $hDBusProxy = DBus[$sDBusName][$sDBusObjectPath]
[40]     SetLEDColor(picStatus, "green")
[41]     $bInspectable = True
[42]     $hDBusSignal = New DBusSignal(DBus.Session, Null, True) As "ObservedSignal"
[43]   Endif
[44]
[45] End
[46]
[47] Public Sub ObservedSignal_Signal(Signal As String, Arguments As Variant[])
[48]
[49]   If Lower(Signal) = "onoff" And If Arguments[0] = "on" Then
[50]      If $iFirst = 0 Then Inc $iFirst
[51]      txaReport.Insert(gb.NewLine)
[52]      txaReport.Insert("   " & ("The data server is online!") & gb.NewLine)
[53]      txaReport.Pos = txaReport.Length
[54]      $bInspectable = True
[55]      SetLEDColor(picStatus, "green")
[56]      SendSound("on.wav")
[57]   Endif
[58]   If Lower(Signal) = "onoff" And If Arguments[0] = "off" Then
[59]      txaReport.Insert(gb.NewLine & gb.NewLine)
[60]      txaReport.Insert("   " & ("The data server is down!") & gb.NewLine)
[61]      txaReport.Pos = txaReport.Length
[62]      $bInspectable = False
[63]      SetLEDColor(picStatus, "red")
[64]      SendSound("off.wav")
[65]   Endif
[66]
[67] End
[68]
[69] Private Sub GetData()
[70]
[71] '  <interface name="org.gambas.dbusserver2.msservice">
[72] '    <method name="GetT">
[73] '      <arg name="arg1" type="s"/>
[74] '      <arg name="value" type="(iiiava{sv})" direction="out"/>
[75] '    </method>
[76] '  </interface>
[77]
[78]   Dim R As Variant[] ' Result
[79]
[80]   R = $hDBusProxy.GetT(Left(cmbScale.Text))
[81]
[82]   ' Print R[0]        ' Sensor Number/Type
[83]   ' Print R[1]        ' Day     15
[84]   ' Print R[2]        ' Month   12
[85]   ' Print R[3]        ' Year    2017
[86]   ' Print R[4][0]     ' Hour    15
[87]   ' Print R[4][1]     ' Minute  24
[88]   ' Print R[4][2]     ' Second   37
[89]   ' Print R[4][3]     ' Time zone "LocelTime"
[90]   ' Print R[5]["T"]   ' Temperature 22.4
[91]   ' Print R[5]["L"]   ' Label       °
[92]   ' Print R[5]["S"]   ' Scale       C
[93]
[94]   $hDate = Date(R[3], R[2], R[1], R[4][0], R[4][1], R[4][2])
[95]
[96]   txaReport.Insert(gb.NewLine)
[97]   If k = 0 Then
[98]      $sReportLine = "   " & R[0] & "   | " & R[4][3] & gb.NewLine & gb.NewLine
[99]      txaReport.Insert($sReportLine)
[100]      Inc k
[101]   Endif
[102]   $sReportLine = "   " & Format($hDate, "dd. mmmm yyyy  -  hh:nn:ss")
[103]   $sReportLine &= " Uhr"
[104]   $sReportLine &= "   |   " & ("Temperature") & " =  "
[105]   If cmbScale.Text = "Kelvin" Then
[106]      $sReportLine &= Format(R[5]["Temperature"], "0.#0") & " " & R[5]["Label"] & R[5]["Scale"]
[107]   Else
[108]      $sReportLine &= Format(R[5]["Temperature"], "+0.#0") & " " & R[5]["Label"] & R[5]["Scale"]
[109]   Endif
[110]   txaReport.Insert($sReportLine)
[111]   txaReport.Pos = txaReport.Length
[112]
[113] End
[114]
[115] Public Sub btnGetData_Click()
[116]   If DBus.Session.Applications.Exist($sDbusName) Then
[117]      SetLEDColor(picStatus, "green")
[118]      GetData()
[119]      $bInspectable = True
[120]   Else
[121]      SetLEDColor(picStatus, "red")
[122]   Endif
[123] End
[124]
[125] '' Sends a sound<br>
[126] '' Sound: Name of the sound file in the project folder 'sounds'.<br>
[127] '' Play back audio files on a PulseAudio sound server - the player is 'paplay'
[128] Public Sub SendSound(SoundFileName As String)
[129]   If System.Exist("paplay") Then
[130]      Shell "paplay " & Application.Path &/ "sounds" &/ SoundFileName
[131]   Endif
[132] End
[133]
[134] Private Sub SetLEDColor(picBox As PictureBox, sLEDColor As String)
[135]   picBox.Picture = Picture["LED/led_" & sLEDColor & ".svg"]
[136] End
[137]
[138] Public Sub btnIntrospektion_Click()
[139]   If $bInspectable = True Then FIntrospection.Show()
[140] End
[141]
[142] Public Sub Form_Close()
[143]   If $hDBusSignal Then $hDBusSignal.Enabled = False
[144]   FMain.Close()
[145] End

Comment:

  • In line 17, it is checked whether the application with the D-Bus name org.gambas.dbusserver2 exists on the session bus. If so, after the assignment in line 31, a proxy is created in line 39 and worked with.
  • In the procedure GetData() in line 80, the method GetT(ShortScale As String) implemented in the D-Bus object “/MSService” is called with one of the three possible arguments and the return value is read into the variable R with the complex data type.
  • Subsequently, all (partial) data are extracted and displayed according to the known signature “(siiiava{sv})” in lines 94 to 111.

24.9.8.2.3 Deployment of Server and Client

Server

B1
Figure 24.9.8.2.1: Server GUI

The server is started, exports a D-bus object to the session D-bus with the implemented service and waits for requests from d-bus enabled clients.

The presented client uses the offered service of the server:

B2
Figure 24.9.8.2.2: Client GUI

B3
Figure 24.9.8.2.3: Two temperature queries

A ComboBox allows you to specify the argument for the method call so that the temperature values are retrieved in the temperature scale so specified. The conversion is done on the server and is part of the service provided.

B4
Figure 24.9.8.2.4: The server is switched off

You will be informed visually and acoustically at all times about the shutdown or a successful restart of the server by the permanent monitoring of the signal “OnOff” by the client.

B5
Figure 24.9.8.2.5: The server is online again


Figure 24.9.8.2.6: The service continues to be used …

At any time you can get information about the implemented method, its signature and the input parameter via an implemented introspection, which is realised by clicking on the i-button. You can also close the window with the ESC key.


Figure 24.9.8.2.7: Successful Introspection of the “/MSService” Object

The following image shows the use of the d-feet programme to use the server's service:

DFEET
Figure 24.9.8.2.8: Method call with argument 'F'.

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k24/k24.9/k24.9.8/k24.9.8.2/start.txt · Last modified: 16.08.2022 (external edit)

Page Tools