1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
<html>
<head>
<title>Gypsy Tutorial</title>
<style type="text/css">
.header {
border-bottom: 1px solid;
padding-bottom: 5;
}
h1 {
font-size: 32px;
font-style: bold;
}
h2 {
font-size: 12px;
font-style: bold;
}
.code {
font-family: fixed, monospace;
font-size: 11px;
border: 1px dashed black;
background: #AAAAAA;
padding: 4px;
white-space: pre;
}
.function {
font-style: italic;
}
</style>
</head>
<body>
<div class="header">
<h1>Libgypsy Tutorial</h1>
<h2>By Iain Holmes <<a href="mailto:iain@gnome.org">iain@gnome.org</a>></h2>
</div>
<p>
Gypsy is made up of two seperate parts, gypsy-daemon and Libgypsy. The former is a daemon that runs in the background, connects to the GPS devices when told to by a client and parses the GPS data into a format that clients can easily deal with.
</p>
<p>
Libgypsy is a wrapper library to the Gypsy D-Bus interface providing GObjects that emit signals as the information they represent changes. The advantage of having many objects rather than one large object is that if a program does not care about, for example, the satellite information then it will not be woken up when Gypsy emits a satellite change signal. This allows programs to sleep more often lowering their power consumption.
</p>
<p>
<h2>Using Libgypsy in a program</h2>
</p>
<p>
Libgypsy provides a Pkgconfig file so that checking for libgypsy and getting the correct compiler and linker flags is simple. The following lines added to a program's configure.ac file will set it all up
</p>
<p class="code">
PKG_CHECK_MODULES(GYPSY, [gypsy])
AC_SUBST(GYPSY_CFLAGS)
AC_SUBST(GYPSY_LIBS)
</p>
<p>
The variables GYPSY_CFLAGS and GYPSY_LIBS then need to be added to the program's Makefiles (or Makefile.am if the program uses automake) to add them in the right place.
</p>
<p>
Libgypsy's header files are all stored in the gypsy subdirectory so if the program needs to use the <a href="reference/html/GypsyDevice.html">GypsyDevice</a> object, it would be included like so:
</p>
<p class="code">
#include <gypsy/gypsy-device.h>
</p>
<p>
The same idea applies for all the other header files.
</p>
<p>
<h2>Creating a Simple GPS program with Libgypsy</h2>
</p>
<p>
When using Libgypsy the first thing a program needs to do is to tell the gypsy-daemon which device to connect to. This is done with the <a href="reference/html/GypsyControl.html">GypsyControl</a> object.
</p>
<p>
<a href="reference/html/GypsyControl.html">GypsyControl</a> is an object that controls the gypsy-daemon, telling it to create or destroy connections to GPS devices. <a href="reference/html/GypsyControl.html">GypsyControl</a> is a singleton object, meaning that there can only be one per program. This object is obtained with the function <span class="function">gypsy_control_get_default</a>. This object is referenced by every call to <span class="function">gypsy_control_get_default</span> and so the program should call g_object_unref on it when the program is finished with it so that gypsy-daemon knows when it is able to clean up.
</p>
<p>
After obtaining a <a href="reference/html/GypsyControl.html">GypsyControl</a> object, gypsy-daemon needs to be told what GPS unit the program wishes to access. Gypsy can refer to GPS devices by both a device path (like /dev/gps) or by Bluetooth address (such as 00:11:22:33:44). This allows Bluetooth devices to be connected to without having to set up the rfcomm connection first. To do this, the program uses the function <span class="function">gypsy_control_create</span>. This function takes three parameters, the <a href="reference/html/GypsyControl.html">GypsyControl</a> object, the device address and a pointer to a GError. It returns the D-Bus path to the GPS object. This path is important as it is how the program knows how to access the various interfaces that gypsy-daemon provides.
</p>
<p>
The simple GPS program now looks like this
</p>
<p class="code">
int main (int argc, char **argv)
{
GypsyControl *control;
GError *error = NULL;
char *path;
/* Libgypsy uses GObject, so the type system needs
to be started up before any Gypsy calls */
g_type_init ();
/* Retrieve the default control */
control = gypsy_control_get_default ();
/* Tell gypsy-daemon to create a GPS object
The GPS to use is passed in as a command line argument */
path = gypsy_control_create (control, argv[1], &error);
if (path == NULL) {
g_warning ("Error creating client for %s: %s,
argv[1], error->message);
return 0;
}
}
</p>
<p>
Gypsy now knows what GPS it should be listening to, but the program needs to start listening as well. Remember that programs using Gypsy only get woken up when the signals that they have expressed an interest in are triggered. Creating objects is the way to show D-Bus which signals the program is interested in. Currently the objects that exist are
<ul>
<li><a href="reference/html/GypsyPosition.html">GypsyPosition</a> - for getting location information</li>
<li><a href="reference/html/GypsyCourse.html">GypsyCourse</a> - for getting course information</li>
<li><a href="reference/html/GypsyAccuracy.html">GypsyAccuracy</a> - for getting accuracy information</li>
<li><a href="reference/html/GypsySatellite.html">GypsySatellite</a> - for getting satellite information</li>
</ul>
A simple GPS just needs to know the location, so a <a href="reference/html/GypsyPosition.html">GypsyPosition<a/> object is created using the path that <span class="function">gypsy_control_create</span> returned. All the objects are created in this way. The simple GPS program now becomes
</p>
<p class="code">
. . .
GypsyPosition *position;
. . .
position = gypsy_position_new (path);
g_signal_connect (position, "position-changed",
G_CALLBACK (position_changed), NULL);
. . .
</p>
<p>
Now, whenever gypsy-daemon emits a PositionChange signal, the position_changed callback will be called. This callback looks like this:
</p>
<p class="code">
static void
position_changed (GypsyPosition *position,
GypsyPositionFields fields_set,
int timestamp,
double latitude,
double longitude,
double altitude,
gpointer userdata)
{
g_print ("%d: %2f, %2f (%1fm)\n", timestamp,
(fields_set & GYPSY_POSITION_FIELDS_LATITUDE) ? latitude :-1.0,
(fields_set & GYPSY_POSITION_FIELDS_LONGITUDE) ? longitude :-1.0,
(fields_set & GYPSY_POSITION_FIELDS_ALTITUDE) ? altitude : -1.0);
}
</p>
<p>
The fields_set parameter is a bitfield which tells the callback which of the following latitude, longitude and altitude parameters contain valid data. This allows the callback to only print out valid locations by checking which bits are set.
</p>
<p>
Finally the program just needs to be able to tell gypsy-daemon that it should start the GPS and retrieve a fix. To do this a <a href="reference/html/GypsyDevice.html">GypsyDevice</a> is created. <a href="reference/html/GypsyDevice.html">GypsyDevice</a> is an object that contains methods and signals related to the actual physical device; being able to start or stop it, whether or not it is connected and the fix status. To start the device:
</p>
<p class="code">
. . .
GypsyDevice *device;
. . .
device = gypsy_device_new (path);
gypsy_device_start (device, &error);
if (error != NULL) {
g_warning ("Error starting %s: %s", argv[1],
error->message);
return 0;
}
. . .
</p>
<p>
As Libgypsy uses GObject it needs to have a mainloop running so that signals can be processed, so it needs this added before it is complete:
</p>
<p class="code">
. . .
GMainLoop *mainloop;
. . .
mainloop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (mainloop);
. . .
</p>
<p>
Obviously if Libgypsy is being used inside a GTK+ program then it will have a mainloop and the GObject type system will be initialised already.
</p>
</body>
</html>
|