DBus Examples#
To call a DBus method, send a signal or introspect the bus, you can use the gdbus tool.
Writing a DBus Daemon#
The specific method to write a DBus daemon will depend on your language of choice, but here is an overview for C.
The introspection file#
The first step in this journey is to describe your interface as a DBus Introspection XML file, as described at gnome_gdbus_codegen. This file will be used to automatically generate interface code in a variety of languages, including C with glib-2.0 and Qt.
An introspection file looks like this:
1<!--SPDX-FileCopyrightText: (C) 2022 Avnet Embedded GmbH-->
2<!--SPDX-License-Identifier: LicenseRef-Avnet-OSS-1.0-->
3<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" >
4<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
5<interface name="com.avnet.embedded.examples.generic_daemon">
6<method name="do_something" />
7</interface>
8</node>
This introspection file is extremely simple and does not exhibit all possibilities, but as a general rule, contained in the main node element should be:
- One or more interfaces and their associated name
- One or more methods and their associated names
0 or more arguments, with direction “in”, “out” or “inout” and their associated names and types. Note that you can have multiple “out” and “inout” arguments. For type descriptions and how to use complex types, please refer to dbus_introspection_format.
- 0 or more signals and their associated names
0 or more arguments and their associated names and types. The direction is omitted there as it’s only outgoing.
0 or more properties and their associated names and types
0 or more children nodes
Names are restricted:
Interface names must always be “reverse domain names” (think Java classes naming convention).
The names of the signals, methods and properties can only contain alphanumeric characters and underscores and can’t start with a number.
You can comment the elements in the XML file by adding a <doc:doc>
element inside it.
Generating the code#
Once that introspection file is finished, use gdbus-codegen
to generate the corresponding interface code.
See the CMakeLists custom commands.
Glueing the generated code to your own project#
To use the interface code, you will want:
A GLib main loop
Several handlers, one for each method you defined
Your main function will look like this:
1 int main (int argc, char* argv[])
2 {
3 guint owner_id = 0;
4 GError *error = NULL;
5
6 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, "com.avnet.embedded.examples.generic_daemon",
7 G_BUS_NAME_OWNER_FLAGS_NONE,
8 on_bus_acquired,
9 on_name_acquired,
10 on_name_lost,
11 NULL,
12 NULL);
13
14 GMainLoop * main_loop = g_main_loop_new(NULL, false);
15 g_main_loop_run(main_loop);
16 g_bus_unown_name(owner_id);
17
18 return 0;
19 }
The first thing we do here is creating a new “skeleton” for out interface. A skeleton is an object that will represent your underlying methods on DBus.
We then connect to the system bus and register our daemon on it (with
com.avnet.embedded.examples.generic_daemon
as it’s name).We register the
do_something
callback, tied to thehandle-do_something
action. If you remember well, we’ve exposed ado_something
method in our introspection file. You can register many more callbacks here, but they should all be prefixed byhandle
.Then we export our skeleton on the bus to be reachable at the
/daemon
path,And then we start the main loop.
Note
For SimpleSwitch™ packages please use simpleswitch.com.avnet.embedded.examples.generic_daemon
for the bus name.
In general, you will also want to start a couple threads or forks to handle things that would block the main thread or process.
Callbacks have the following shape:
1 static gboolean do_something(
2 ComAvnetEmbeddedExamplesGeneric_daemon *interface,
3 GDBusMethodInvocation *invocation,
4 gpointer user_data)
5 {
6 do_something();
7
8 com_avnet_embedded_examples_generic_daemon_complete_do_something(interface, invocation);
9
10 return true;
11 }
They’re really just glue for your underlying code. Here, do_something
is our own function,
and the complete
function was generated by gdbus-codegen
.
The callback’s type and the complete
function’s type will depend on your method signature,
specifically the in
, inout
and out
parameters.
To send a signal, you can use the following functions: <object name>_emit_<signal name>(skeleton, [parameters]);
.
These functions will be automatically generated for every signal you add to your introspection XML.
You can call them from anywhere in your program with the your object skeleton.
References#
For more information, please visit the following links: