Libgps to extract data from gpsd daemon

I wanted to use libgps to interact with gpsd daemons. This is why I implemented a small test application to extract the value from a specific satellite.

The documentation on the HOWTO page tells us that

The tricky part is the interpretation of what you get from reading the lock. The reason this is complicated is because you did not guarantee that each read would select exactly one complete JSON object from the daemon. This can capture one response object or more than one, or part of one or one, or a fragment follows.

As recommended in the documentation, the PACKET_SET mask PACKET_SET checked before doing anything else.

 #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdint.h> #include <gps.h> #include <pthread.h> pthread_t t_thread; struct t_args { unsigned int ID; }; unsigned int status = 0; int elevation; int p_nmea(void *targs); void start_test(void) { struct t_args *args = malloc(sizeof *args); status = 1; args->ID = 10; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (pthread_create(&t_thread, &attr, (void *)&p_nmea, args) != 0) { perror("create: \n"); } } int test_result(int * Svalue) { int res; if(status == 1) { void * t_res; if(pthread_tryjoin_np(t_thread, &t_res) != 0) { status = 1; } else { if((int)t_res == 1) { res = 3; *Svalue = elevation; elevation = 0; } else { res = 4; } } } return res; } int p_nmea(void *targs) { struct t_args *thread_args = targs; struct gps_data_t gpsdata; int ret = -1; int count = 10; int i,j; if(gps_open((char *)"localhost", (char *)DEFAULT_GPSD_PORT, &gpsdata) != 0) { (void)fprintf(stderr, "cgps: no gpsd running or network error: %d, %s\n", errno, gps_errstr(errno)); return (-1); } else { (void)gps_stream(&gpsdata, WATCH_ENABLE, NULL); do { if(!gps_waiting(&gpsdata, 1000000)) { (void)gps_close(&gpsdata); } else { if(gps_read(&gpsdata) == -1) { return (-1); } else { if(gpsdata.set & PACKET_SET) { for (i = 0; i < MAXCHANNELS; i++) { for (j = 0; j < gpsdata->satellites_visible; j++) { if(gpsdata->PRN[i] == thread_args.ID) { elevation = (int)gpsdata->elevation[i]; ret = 1; break; } } if(gpsdata->PRN[i] == thread_args.ID) { break; } } } } } --count; }while(count != 0); } (void)gps_stream(&gpsdata, WATCH_DISABLE, NULL); (void)gps_close(&gpsdata); (void)free(thread_args); (void)pthread_exit((void*) ret); } 

As recommended in the documentation, I looked at cgps and gpxlogger, for example, at codes, but because of the subtleties of libgps, they avoid me. A while loop has been added before gps_waiting() to get at least one whole response object. Before introducing pthread, I noticed that calling the test_result() function immediately after start_test() would take a few seconds before returning a response. Using the thread, I thought that 3 would be returned immediately, then 3 or 4 .. but it is not! I'm still losing a few seconds. Also, I voluntarily use pthread_tryjoin_np() because its man page says

Pthread_tryjoin_np () performs a non-blocking connection to a thread

Can someone give me their help, I think that I understand something wrong, but I still can not say about which part? Basically, why do I return to the do while loop at least four times before returning the first value?

EDIT 1:

After reading the HOWTO document, highlight the lines again:

The fact that checking for data expectations and reading both blocks means that if your application needs to deal with input sources other than GPS, you probably have to isolate the read cycle in the stream with the mutex lock on the gps_data structure.

I'm a little confused. What does it mean?

+6
source share
1 answer

Your cycle runs several times before returning the full package because you do not have a sleep state. Therefore, every time the daemon registers a packet (even if it is not a complete NMEA message), the gps_waiting() function is returned. I would recommend sleeping at least until the GPS logs the full message.

For example, if you are expecting a GPPAT message, you can reasonably expect the message to have 12 characters. Thus, at 9600 bauds, it will take 1 / 17.5 seconds or about 57 ms. In this case, your code might look like this:

 #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdint.h> #include <gps.h> #include <pthread.h> pthread_t t_thread; struct t_args { unsigned int ID; }; unsigned int status = 0; int elevation; int p_nmea(void *targs); void start_test(void) { struct t_args *args = malloc(sizeof *args); status = 1; args->ID = 10; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (pthread_create(&t_thread, &attr, (void *)&p_nmea, args) != 0) { perror("create: \n"); } } int test_result(int * Svalue) { int res; if(status == 1) { void * t_res; if(pthread_tryjoin_np(t_thread, &t_res) != 0) { status = 1; } else { if((int)t_res == 1) { res = 3; *Svalue = elevation; elevation = 0; } else { res = 4; } } } return res; } int p_nmea(void *targs) { struct t_args *thread_args = targs; struct gps_data_t gpsdata; int ret = 0; int count = 10; int i,j; if(gps_open((char *)"localhost", (char *)DEFAULT_GPSD_PORT, &gpsdata) != 0) { (void)fprintf(stderr, "cgps: no gpsd running or network error: %d, %s\n", errno, gps_errstr(errno)); return (-1); } else { (void)gps_stream(&gpsdata, WATCH_ENABLE, NULL); do { ret = 0; // Set this here to allow breaking correctly usleep(50000); // Sleep here to wait for approx 1 msg if(!gps_waiting(&gpsdata, 1000000)) break; if(gps_read(&gpsdata) == -1) break; if(gpsdata.set & PACKET_SET) { for (i = 0; i < MAXCHANNELS && !ret; i++) { for (j = 0; j < gpsdata.satellites_visible; j++) { if(gpsdata.PRN[i] == thread_args.ID) { elevation = (int)gpsdata.elevation[i]; // Be sure to not deref structure here ret = 1; break; } } } --count; }while(count != 0); } (void)gps_stream(&gpsdata, WATCH_DISABLE, NULL); (void)gps_close(&gpsdata); (void)free(thread_args); (void)pthread_exit((void*) ret); } 

Alternatively, you can simply set your account higher and wait for the full message.

0
source

All Articles