6

我想使用 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 的微妙之处让我无法理解。之前添加了一个 while 循环gps_waiting(),以便至少获取一个完整的响应对象。在介绍 pthread 之前,我注意到在返回答案之前需要几秒钟test_result()后调用该函数。start_test()通过使用我认为3会立即返回的线程,然后34.. 但事实并非如此!我仍然失去了几秒钟。另外,我自愿使用pthread_tryjoin_np(),因为它的手册页说

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

谁能给我他的帮助,我想我理解错了,但我还不能说哪一部分?基本上,为什么我在返回第一个值之前至少要进入 do while 循环四次?

编辑 1:

再次阅读文档 HOWTO 后,我突出显示以下几行:

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

我有点困惑。它的真正含义是什么?

4

1 回答 1

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

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

于 2016-04-04T23:56:34.413 回答