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

ogs*_*ogs 6 c parsing gps json 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);
}
Run Code Online (Sandbox Code Playgroud)

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

pthread_tryjoin_np()函数与线程执行非阻塞连接

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

编辑1:

在再次阅读文档HOWTO之后,我突出了以下几行:

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

我有点困惑.它到底意味着什么?

Set*_*eth 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);
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以将计数设置得更高并等待完整消息。