Location framework

Location framework provides a library called liblocation which is used for developing location aware applications in Fremantle. Liblocation supports internal GPS, network based methods and external bluetooth GPS.

Using liblocation

To start implementing applications using liblocation API, you have to include the following headers.

#include <location/location-gps-device.h>
#include <location/location-gpsd-control.h>

Liblocation has two public GObjects. LocationGPSDControl is used for starting and stopping of location services, setting location method and interval, and listening for errors. LocationGPSDevice has information about device status and contains the actual fix when one exists. The two GObjects are initiated as follows.

LocationGPSDControl *control = location_gpsd_control_get_default();
LocationGPSDevice *device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);

Location methods

Liblocation supports the following location methods which are defined in location-gpsd-control.h.

  • LOCATION_METHOD_USER_SELECTED
    Liblocation will choose the best possible location method based on location settings in control panel. If both gps and network positioning are enabled, then this will equal to ACWP+AGNSS. Choose this method if you don't have any special needs.
  • LOCATION_METHOD_CWP - Complementary Wireless Positioning
    The least accurate method with latitude and longitude of the fix pointing to the center of current country and horizontal accuracy being roughly radius of the country. SIM card is needed for CWP method.
  • LOCATION_METHOD_ACWP - Assisted Complementary Wireless Positioning
    A method where device is located based on cellular base station, device is registered to. SIM card and a network connection is needed for ACWP method. If no network connection is available, this equals to CWP. Application might receive CWP fixes before base station information from external location server is fetched.
  • LOCATION_METHOD_GNSS - Global Navigation Satellite System
    A method for using GPS receiver. Typically time for the first fix is significantly longer than with AGNSS. Neither SIM card nor network connection is needed for GNSS method, and GNSS can even be used in offline mode.
  • LOCATION_METHOD_AGNSS - Assisted Global Navigation Satellite System
    A method for using GPS receiver with assistance data from external location server. A SIM card and a network connection is needed for AGNSS method. If no network connection or SIM card is available, this equals to GNSS.

Location resources are shared between applications, and applications can request different location methods. Fixes for all requested methods are sent for all applications listening to liblocation "changed" signal, therefore application should judge whether fix it is receiving, is one that it needs. See LocationGPSDeviceFix chapter for discussion.

If device is set for bluetooth GPS from control panel, it can used for locationing via USER_SELECTED, AGNSS and GNSS methods. In this case AGNSS and GNSS do not differ, because assistance server cannot be utilized.

Device caches cell information for ACWP and satellite information for AGNSS. Hence if a non-assisted location method is used immediately after it's assisted counterpart, it will probably work as the assisted one.

Location method is set as LocationGPSDControl's "preferred-method" property. Several methods can be given by bitwise or'ing the method identifiers:

g_object_set(G_OBJECT(control), "preferred-method", LOCATION_METHOD_ACWP | LOCATION_METHOD_AGNSS, NULL);

Here is table that summarizes differences between the methods. Accuracy refers to horizontal accuracy of the fix.

Method Typ Accuracy Req SIM Req NW Drains Bat
CWP 100km-1000km Yes No No
ACWP 1km-10km Yes Yes No
GNSS 1m-100m No No Yes
AGNSS 1m-100m Yes Yes Yes

Location intervals

Liblocation supports a default interval and intervals of 1, 2, 5, 10, 20, 30, 60 and 120 seconds between fixes. These are defined in location-gpsd-control.h. Default interval means that several fixes are only sent when device's position changes, therefore it is a good choice for power consumption aware applications, and should be used if application doesn't have any special needs.

Due to the fact that location resources are shared between applications, setting interval to e.g. 5 seconds doesn't necessarily guarantee that you are getting fixes at 5 second interval, but the maximum time between fixes is 5 seconds.

Location interval is set as LocationGPSDControl's "preferred-interval" property:

g_object_set(G_OBJECT(control), "preferred-interval", LOCATION_INTERVAL_60S, NULL);

LocationGPSDevice and LocationGPSDeviceFix

LocationGPSDevice object has the following public fields:

  • gboolean online: Whether there is a connection to the hardware
  • LocationGPSDeviceStatus status: Status of the device
  • LocationGPSDeviceFix *fix: The actual fix (latitude, longitude, etc)
  • int satellites_in_view: Number of satellites in view
  • int satellites_in_use: Number of satellites in use
  • GPtrArray *satellites: Array of satellites
  • LocationCellInfo *cell_info: Information about cell the device is connected to

The most useful field is naturally "fix" which contains position and movement of the device and accuracies for them. LocationGPSDeviceFix fields are listed below. In parenthesis there is a identifier which can be bitwisely anded with "fields" field, to see whether corresponding field is set.

  • LocationGPSDeviceMode mode: The mode of the fix
  • guint32 fields: A bitfield representing what fields contain valid data
  • double time: The timestamp of the update (LOCATION_GPS_DEVICE_TIME_SET)
  • double ept: Time accuracy
  • double latitude: Fix latitude (LOCATION_GPS_DEVICE_LATLONG_SET)
  • double longitude: Fix longitude (LOCATION_GPS_DEVICE_LATLONG_SET)
  • double eph: Horizontal position accuracy
  • double altitude: Fix altitude in meters (LOCATION_GPS_DEVICE_ALTITUDE_SET)
  • double epv: Vertical position accuracy
  • double track: Direction of motion in degrees (LOCATION_GPS_DEVICE_TRACK_SET)
  • double epd: Track accuracy
  • double speed: Current speed in km/h (LOCATION_GPS_DEVICE_SPEED_SET)
  • double eps: Speed accuracy
  • double climb: Current rate of climb in m/s (LOCATION_GPS_DEVICE_CLIMB_SET)
  • double epc: Climb accuracy

An application receiving a fix cannot know if the fix is a result from location method it requested. Therefore application should study whether fix is accurate enough to satisfy application's needs. This can be done by inspecting "eph" field, which is fix's horizontal accuracy in centimeters. Typical values for horizontal accuracies can be seen in the location methods table. If accuracy is not known, it has a value of NaN.

Liblocation signals and callbacks

The most useful signal in liblocation is LocationGPSDevice's "changed" signal, which is emitted everytime a new fix is received. LocationGPSDControl has an "error" signal which is emitted in case of an error. You can connect to these signals in the usual way:

g_signal_connect(control, "error", G_CALLBACK(on_error), user_data);
g_signal_connect(device, "changed", G_CALLBACK(on_changed), user_data);

Below is an example for these signals' callbacks.

static void on_error(LocationGPSDControl *control, gpointer user_data)
{
g_debug("Location error");
}

static void on_changed(LocationGPSDevice *device, gpointer user_data)
{
if (!device)
return;

if (device->fix) {
if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET)
g_debug("lat = %f, long = %f", device->fix->latitude, device->fix->longitude);

if (device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET)
g_debug("alt = %f", device->fix->altitude);

g_debug("horizontal accuracy: %f meters", device->fix->eph/100);
}

if (device && device->cell_info) {
if (device->cell_info->flags & LOCATION_CELL_INFO_GSM_CELL_INFO_SET)
g_debug("Mobile Country Code GSM: %d", device->cell_info->gsm_cell_info.mcc);

if (device->cell_info->flags & LOCATION_CELL_INFO_WCDMA_CELL_INFO_SET)
g_debug("Mobile Country Code WCDMA: %d", device->cell_info->wcdma_cell_info.mcc);
}

g_debug("Satellites in view: %d, in use: %d",
device->satellites_in_view, device->satellites_in_use);
}

Liblocation sends a "changed" signal also after locationing is started or stopped, in which case a last known fix is sent if such exists. Application can differentiate these fixes from real ones by inspecting device->status field which equals LOCATION_GPS_DEVICE_STATUS_NO_FIX if the fix is not real.

Starting and stopping locationing

Finally after everything above has been done, locationing can be started.

location_gpsd_control_start(control);

If the chosen location method violates control panel location settings, then a dialog is shown to user. Dialogs ask user to enable necessary services. On user's refusal an error to application is sent. If no error is seen, fixes should be coming after a while. When locationing is no longer needed, it can be stopped.

location_gpsd_control_stop(control);

Complete example

Here is a complete standalone example using liblocation. It starts location services after program is started, then when first fix arrives, prints it, stops services, and shutdowns.

#include <location/location-gps-device.h>
#include <location/location-gpsd-control.h>

static void on_error(LocationGPSDControl *control, gpointer data)
{
g_debug("location error... quitting");
g_main_loop_quit((GMainLoop *) data);
}

static void on_changed(LocationGPSDevice *device, gpointer data)
{
if (!device)
return;

if (device->fix) {
if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
g_debug("lat = %f, long = %f", device->fix->latitude, device->fix->longitude);
location_gpsd_control_stop((LocationGPSDControl *) data);
}
}
}

static void on_stop(LocationGPSDControl *control, gpointer data)
{
g_debug("quitting");
g_main_loop_quit((GMainLoop *) data);
}

static gboolean start_location(gpointer data)
{
location_gpsd_control_start((LocationGPSDControl *) data);
return FALSE;
}

int main(int argc, char *argv[])
{
LocationGPSDControl *control;
LocationGPSDevice *device;
GMainLoop *loop;

g_type_init();

loop = g_main_loop_new(NULL, FALSE);

control = location_gpsd_control_get_default();
device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);

g_object_set(G_OBJECT(control),
"preferred-method", LOCATION_METHOD_USER_SELECTED,
"preferred-interval", LOCATION_INTERVAL_DEFAULT,
NULL);

g_signal_connect(control, "error", G_CALLBACK(on_error), loop);
g_signal_connect(device, "changed", G_CALLBACK(on_changed), control);
g_signal_connect(control, "gpsd-stopped", G_CALLBACK(on_stop), loop);

g_idle_add(start_location, control);

g_main_loop_run(loop);

g_object_unref(device);
g_object_unref(control);

return 0;
}

You can compile this example with following command:

gcc -Wall `pkg-config --cflags glib-2.0,liblocation --libs glib-2.0,liblocation` -o example example.c