11

I am writing a number-crunching data-logging C program for my GPS enabled Raspberry Pi. I grabbed gpsd, and its sample app cgps displays gps information correctly. I wanted to use libgps to interface with the daemon so that I could have all that handy information in my app, but I was quickly overwhelmed by the complexity of its API.

The documentation on its HOWTO page points me to look at cgps and gpxlogger for example code, but there's so much coupling that I can't wade through it all. On the opposite end of the spectrum, the C code example on the libgps page is so stripped back that it's unusable.

Can anybody point me to a single class sample that might demystify this? Perhaps something that contains a getCoordinates() function?

JamesB192
  • 3
  • 2
Nathan Vance
  • 605
  • 1
  • 5
  • 21

2 Answers2

18

I spoke too soon. After browsing other SO questions, I ran into this completely unrelated question. Here's my very slightly modified version:

#include <gps.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>

int main() {
struct timeval tv;
struct gps_data_t gps_data;

if ((gps_open("localhost", "2947", &gps_data)) == -1) {
    printf("code: %d, reason: %s\n", errno, gps_errstr(errno));
    return EXIT_FAILURE;
}
gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);

while (1) {
    /* wait for 2 seconds to receive data */
    if (gps_waiting (&gps_data, 2000000)) {
        /* read data */
        if ((gps_read(&gps_data,NULL,0)) == -1) {
            printf("error occured reading gps data. code: %d, reason: %s\n", errno, gps_errstr(errno));
        } else {
            /* Display data from the GPS receiver. */
            if ((gps_data.status == STATUS_FIX) && 
                (gps_data.fix.mode == MODE_2D || gps_data.fix.mode == MODE_3D) &&
                !isnan(gps_data.fix.latitude) && 
                !isnan(gps_data.fix.longitude)) {
                    //gettimeofday(&tv, NULL); EDIT: tv.tv_sec isn't actually the timestamp!
                    printf("latitude: %f, longitude: %f, speed: %f, timestamp: %lf\n", gps_data.fix.latitude, gps_data.fix.longitude, gps_data.fix.speed, gps_data.fix.time); //EDIT: Replaced tv.tv_sec with gps_data.fix.time
            } else {
                printf("no GPS data available\n");
            }
        }
    }

    sleep(3);
}

/* When you are done... */
gps_stream(&gps_data, WATCH_DISABLE, NULL);
gps_close (&gps_data);

return EXIT_SUCCESS;
}

I compile it by running gcc -o gps filename.c -lm -lgps

Nathan Vance
  • 605
  • 1
  • 5
  • 21
  • Do you happen to know how to get gps time? I'm not too familiar with C but `tv.tv_sec` looks like the system time? – Lightsout Nov 02 '16 at 05:40
  • Probably because I should have used `gps_data.fix.time` instead. Thanks for catching that! – Nathan Vance Nov 02 '16 at 16:06
  • 1
    This is a bit late, but it might prove useful to someone else: you should print the timestamp as an `%lf`. In _gps.h_, the `gps_data.fix.time` is defined as a `timestamp_t`, which is just an alias for a double. Perfect answer otherwise! – Cyril C. Oct 18 '17 at 09:46
  • `gps_data.fix.time` is now defined as a `timespec_t` which is a struct timespec with tv_sec and tv_nsec. – solsTiCe Mar 12 '20 at 16:18
  • To get a human readable time: `struct tm ts; time_t time = gps_data->fix.time; char buf[80]; ts = *localtime(&time); strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts); ` – Joel Ravazzolo Mar 24 '20 at 13:55
2

For the sake of completeness I would like to offer the following edited version of Nathan's program which demonstrates the shared memory interface approach. It took me an afternoon of searching to find the missing key to getting this to work.

EDIT: I corrected the way to properly handle errors from gps_open and gps_read using errno.

#include <gps.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>

int main() {
int rc;
//struct timeval tv;
struct gps_data_t gps_data;

if ((gps_open(GPSD_SHARED_MEMORY, NULL, &gps_data)) == -1) {
    printf("code: %d, reason: %s\n", errno, gps_errstr(errno));
    return EXIT_FAILURE;
}

for(int i=0; i<10; i++) {
        /* read data */
        if ((gps_read(&gps_data,NULL,0)) == -1) {
            printf("error occured reading gps data. code: %d, reason: %s\n", errno, gps_errstr(errno));
        } else {
            /* Display data from the GPS receiver. */
            if ((gps_data.status == STATUS_FIX) && 
                (gps_data.fix.mode == MODE_2D || gps_data.fix.mode == MODE_3D) &&
                !isnan(gps_data.fix.latitude) && 
                !isnan(gps_data.fix.longitude)) {
                    printf("latitude: %f, longitude: %f, speed: %f, timestamp: %lf\n", gps_data.fix.latitude, gps_data.fix.longitude, gps_data.fix.speed, gps_data.fix.time);
            } else {
                printf("no GPS data available\n");
            }
        }

    sleep(3);
}

/* When you are done... */
gps_close (&gps_data);

return EXIT_SUCCESS;
}