Ich wollte libgps als Schnittstelle zum gpsd-Daemon verwenden. Aus diesem Grund habe ich eine kleine Testanwendung implementiert, um einen Wert von einem bestimmten Satelliten zu extrahieren.libgps zum Extrahieren von Daten aus dem gpsd-Daemon
Die Dokumentation auf seiner HOWTO Seite sagt uns, dass
Der schwierige Teil ist zu interpretieren, was Sie aus der blockierenden Lese erhalten. Der Grund, warum es schwierig ist, ist, dass Sie nicht garantieren können, dass jedes Lesen genau ein komplettes JSON-Objekt aus dem Daemon abholen wird. Es kann greifen Sie ein Antwortobjekt, oder mehr als eins oder ein Teil von einem oder einem oder mehr gefolgt von einem Fragment.
Wie in der Dokumentation empfohlen, wird das Maskenbit PACKET_SET
überprüft, bevor etwas anderes getan wird.
#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);
}
Wie auch in der Dokumentation empfohlen, ich hatte einen Blick auf CGPS und gpxlogger zum Beispiel Codes, aber die Feinheit der libgps mich entkommen. Eine While-Schleife wurde vor gps_waiting()
hinzugefügt, um mindestens ein gesamtes Antwortobjekt zu erhalten. Bevor ich PThread einführte, bemerkte ich, dass die Funktion kurz nach start_test()
einige Sekunden dauert, bevor sie eine Antwort zurücksendet. Mit einem Thread dachte ich, dass 3
würde sofort zurückgegeben werden, dann 3
oder 4
.. aber es ist nicht! Ich verliere immer noch einige Sekunden. Außerdem verwende ich pthread_tryjoin_np()
freiwillig, weil seine Manpage sagt
Die pthread_tryjoin_np() Funktion ein nicht-blockierende mit dem Gewinde
mir jemand geben kann seine Hilfe verbinden führt, denke ich, dass ich etwas falsch verstehen aber was kann ich noch nicht sagen? Warum komme ich mindestens viermal in die do while-Schleife, bevor ich den ersten Wert zurückgebe?
EDIT 1:
Nach dem Lesen der Dokumentation HOWTO wieder markierte ich die Zeilen:
Die Tatsache, dass die Daten-Warteprüfung und die Lese beide Block bedeuten, dass, wenn Ihre Anwendung zu tun hat Bei anderen Eingangsquellen als dem GPS müssen Sie wahrscheinlich die Leseschleife in einem Thread mit einer Mutex-Sperre für die gps_data-Struktur isolieren.
Ich bin ein bisschen verwirrend. Was bedeutet das wirklich?
Ich bin nicht vertraut mit dem Lesen von Daten von GPS, aber Ihre Threading wie gepostet aussieht wie Ärger. An anderer Stelle rufen Sie 'start_test' und dann' test_result' in der nächsten Zeile an? Und was genau versuchst du zu tun? Höhendaten von GPS Satellit 10 lesen? Ich begann mit einer Antwort, aber es stellte sich heraus, dass ich zu viele Fragen hatte. Ihre zitierte EDIT1-Dokumentation bedeutet einfach, dass Aufrufe von 'gps_waiting()' und 'gps_read()' blockieren. Wenn Sie nur einen einzigen Thread in Ihrem Prozess haben, bedeutet dies, dass Ihr gesamter Prozess zum Stillstand kommt, bis der Aufruf der blockierenden Funktion zurückkehrt. (Forts.) – yano
(Forts.) Wenn also Ihr Prozess auf andere Eingabequellen wartet, verlieren Sie alle Daten, die während der Blockierung Ihres einzelnen Threads auf 'gps_waiting()' und/oder 'gps_read()' eingehen. Aus diesem Grund schlägt es vor, diese Anrufe zu einem separaten Thread zu machen, dessen einzige Aufgabe darin besteht, diese Anrufe zu blockieren und Daten von ihnen abzurufen. Währenddessen sind andere Threads in Ihrem Prozess frei für alles, was Ihr Prozess sonst noch tun möchte. Der Mutex für die 'gps_data'-Struktur wird empfohlen, um den Zugriff darauf zu schützen, falls andere Threads modifizieren und/oder lesen. Mutexe sorgen für die Daten-Parallelität und Integrität in (Forts.) – yano
(Forts.) Multi-Thread-Umgebungen. Wenn Ihnen das alles neu ist, empfehle ich Ihnen, ein Pthread-Tutorial zu lesen. Das ist ein guter Tipp: https://computing.llnl.gov/tutorials/pthreads/. Aber basierend auf dem, was Sie hier versuchen, brauchen Sie vielleicht gar keine Threads. Wenn das nur ein Test/Proof-of-Concept ist, dass Sie tatsächlich GPS-Daten lesen können, würde ich nicht mit Threads herumspielen. Threads fügen immer Komplikationen hinzu und öffnen die Tür für seltsame Bugs, wenn sie nicht richtig verwendet werden. Entschuldigung für den langen Kommentar; Wünschte, SO hätte eine Seite für Antworten und eine Seite zur Diskussion. – yano