用于从gpsd守护程序中提取数据的libgps

时间:2016-02-24 22:23:14

标签: c json parsing gps gpsd

我想使用libgps与gpsd守护进程交互。这就是为什么我实施了一个小测试应用程序以便从特定卫星中提取值的原因。

HOWTO页面上的文档告诉我们

  

棘手的部分是解释阻塞读取的内容。   它很棘手的原因是你无法保证每次阅读   将从守护进程中获取一个完整的JSON对象。有可能   抓取一个响应对象,或多个,或一个,或一个或一部分   更多的是片段。

根据文档建议,在执行任何其他操作之前会检查PACKET_SET掩码位。

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

正如文档中所建议的,我看了cgps和gpxlogger的示例代码,但libgps的微妙之处让我感到震惊。在gps_waiting()之前添加了一个while循环,以便至少获得一个完整的响应对象。在介绍pthread之前,我注意到在test_result()之后调用函数start_test()需要几秒钟才能返回答案。通过使用一个帖子我认为3会立即返回,然后34 ..但它不是!我还在失去几秒钟。另外,我自愿使用pthread_tryjoin_np(),因为其手册页说

  

pthread_tryjoin_np()函数使用线程

执行非阻塞连接

任何人都可以给我他的帮助,我想我理解错误但我无法说出哪一部分呢?基本上,为什么我在返回第一个值之前至少进入do while循环四次?

编辑1:

再次阅读HOWTO文档后,我强调了以下几行:

  

数据等待检查和读取两个块意味着,如果您的应用程序必须处理除GPS以外的其他输入源,您可能必须在具有互斥锁定的线程中隔离读取循环gps_data结构。

我有点困惑。它究竟意味着什么?

1 个答案:

答案 0 :(得分:0)

由于您没有睡眠条件,您的循环在返回完整数据包之前会执行多次。因此,每次守护程序注册数据包(即使不是完整的NMEA消息),gps_waiting()函数返回。我建议至少睡觉,只要你的GPS注册一个完整的消息。

例如,如果您希望发送GPPAT条消息,则可以合理地预期消息中会包含12个字符。因此,在9600波特,这需要1 / 17.5秒或大约57毫秒。在这种情况下,您的代码可能如下所示:

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

或者,你可以设置更高的数量并等待完整的信息。