2016-02-24 18 views
6

Volevo usare libgps per interfacciare il demone gpsd. Ecco perché ho implementato una piccola applicazione di test per estrarre un valore da un satellite specifico.libgps per estrarre i dati dal demone gpsd

La documentazione sulla sua pagina di HOWTO ci dice che

La parte difficile è interpretare ciò che si ottiene dalla lettura di blocco. La ragione è che non è garantito che ogni lettura prelevi esattamente un oggetto JSON completo dal demone. È possibile che acquisisca un oggetto risposta, o più di uno, o parte di uno, o uno o seguito da un frammento.

Come raccomandato nella documentazione, il bit di maschera PACKET_SET viene controllato prima di fare qualsiasi altra cosa.

#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); 
} 

Come raccomandato nella documentazione troppo, ho dato un'occhiata alla CGPS ​​e gpxlogger ad esempio i codici, ma le sottigliezze della libgps mi sfuggono. Un ciclo while è stato aggiunto prima di gps_waiting() per ottenere, almeno, un intero oggetto risposta. Prima di introdurre pthread, ho notato che chiamare la funzione test_result() subito dopo lo start_test() richiedere alcuni secondi prima di restituire una risposta. Usando un thread ho pensato che 3 sarebbe stato restituito immediatamente, quindi 3 o 4 .. ma non lo è! Sto ancora perdendo alcuni secondi. Inoltre, io uso volontariamente pthread_tryjoin_np() perché la sua pagina man dice funzione

Il pthread_tryjoin_np() esegue un bloccante unirsi con il filo

Qualcuno mi può dare il suo aiuto, penso che ho capito qualcosa di sbagliato ma non sono ancora in grado di dire su quale parte? Fondamentalmente, perché vengo nel ciclo do while almeno quattro volte prima di restituire il primo valore?

EDIT 1:

Dopo aver letto di nuovo il HOWTO documentazione evidenzio le linee:

Il fatto che il controllo dei dati di attesa e la lettura sia di blocco significa che, se l'applicazione deve fare i conti con altre sorgenti di input rispetto al GPS, probabilmente dovrai isolare il ciclo di lettura in un thread con un blocco mutex sulla struttura gps_data.

Sono un po 'confuso. Cosa significa veramente?

+0

Non ho familiarità con la lettura dei dati dal GPS, ma il threading come pubblicato sembra un problema. Nel codice altrove stai chiamando 'start_test' quindi' test_result' nella riga successiva? E cosa stai cercando di fare esattamente? Leggi i dati di elevazione dal satellite GPS 10? Ho iniziato una risposta, ma ho scoperto che avevo troppe domande. La tua documentazione citata EDIT1 significa semplicemente che le chiamate a 'gps_waiting()' e 'gps_read()' stanno per bloccare. Se nel processo è presente un solo thread, ciò significa che l'intero processo si arresterà bruscamente fino a quando non verrà restituita la chiamata della funzione di blocco. (segue) – yano

+0

(cont) Quindi se il tuo processo è in attesa su altre sorgenti di input, perderai tutti i dati in arrivo mentre il tuo thread singolo sta bloccando su 'gps_waiting()' e/o 'gps_read()'. Questo è il motivo per cui suggerisce di fare di queste chiamate un thread separato il cui unico compito è semplicemente quello di bloccare queste chiamate e recuperare i dati da esse. Nel frattempo, altri thread nel processo sono gratuiti per qualsiasi altra cosa il tuo processo possa voler fare. Il mutex per la struttura 'gps_data' è raccomandato per proteggere l'accesso ad esso nel caso in cui altri thread stiano modificando e/o leggendo da esso. I mutex assicurano la concorrenza e l'integrità dei dati in (cont) – yano

+0

(segue) ambienti multi-thread. Se tutto questo è nuovo per te, allora ti consiglio di leggere un tutorial di pthread. Questo è buono: https://computing.llnl.gov/tutorials/pthreads/. Ma in base a ciò che stai cercando di fare qui, potresti anche non aver bisogno di discussioni. Se questo è solo un test/proof-of-concept che in effetti puoi leggere i dati GPS, non mi farebbe casini con i thread. I thread aggiungono sempre complicazioni e aprono la porta a strani bug se non usati correttamente. Scusa per il lungo commento; Vorrei che SO avesse una pagina per le risposte e una pagina per la discussione. – yano

risposta

0

Il ciclo è in esecuzione più volte prima di restituire un pacchetto completo perché non si dispone di una condizione di sospensione. Pertanto, ogni volta che il daemon registra un pacchetto (anche quando non è un messaggio NMEA completo), viene restituita la funzione gps_waiting(). Ti consiglio di dormire almeno fino a quando il tuo GPS registrerà un messaggio completo.

Ad esempio, se si prevedono i messaggi GPPAT, è ragionevole prevedere 12 caratteri nel messaggio. Quindi a 9600 baud, ciò richiederebbe 1/17,5 secondi o circa 57 ms.In questo caso, il tuo codice potrebbe essere il seguente:

#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); 
} 

In alternativa, è possibile impostare il conteggio più alto e attendere il messaggio completo.

Problemi correlati