代码拉取完成,页面将自动刷新
/* gpsctl.c -- tweak the control settings on a GPS
*
* This file is Copyright 2010 by the GPSD project
* SPDX-License-Identifier: BSD-2-clause
*
*/
#include "include/gpsd_config.h" // must be before all includes
#include <assert.h>
#include <errno.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for strlcat() and strlcpy()
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h> // for _exit()
#include "include/gpsd.h"
#ifdef SHM_EXPORT_ENABLE
#include <sys/ipc.h>
#include <sys/shm.h>
#endif // SHM_EXPORT_ENABLE
#define HIGH_LEVEL_TIMEOUT 8
static int debuglevel;
static bool explicit_timeout = false;
static unsigned int timeout = 0; // no timeout
static struct gps_context_t context;
static bool hunting = true;
/*
* Set this as high or higher than the maximum number of subtype
* probes in drivers.c.
*/
#define REDIRECT_SNIFF 15
// allow the device to settle after a control operation
static void settle(struct gps_device_t *session)
{
struct timespec delay;
/*
* See the 'deep black magic' comment in serial.c:set_serial().
*/
(void)tcdrain(session->gpsdata.gps_fd);
// wait 50,000 uSec
delay.tv_sec = 0;
delay.tv_nsec = 50000000L;
nanosleep(&delay, NULL);
(void)tcdrain(session->gpsdata.gps_fd);
}
/*
* Allows any response other than ERROR. Use it for queries where a
* failure return (due to, for example, a missing driver method) is
* immediate, but successful responses have unpredictable lag.
*/
#define NON_ERROR 0 // must be distinct from any gps_mask_t value
// send a query to gpsd and wait on an expected response type
static bool gps_query(struct gps_data_t *gpsdata,
gps_mask_t expect,
const int timeout,
const char *fmt, ... )
{
static fd_set rfds;
char buf[BUFSIZ];
va_list ap;
time_t starttime;
struct timespec tv;
sigset_t oldset, blockset;
(void)sigemptyset(&blockset);
(void)sigaddset(&blockset, SIGHUP);
(void)sigaddset(&blockset, SIGINT);
(void)sigaddset(&blockset, SIGTERM);
(void)sigaddset(&blockset, SIGQUIT);
(void)sigprocmask(SIG_BLOCK, &blockset, &oldset);
va_start(ap, fmt);
(void)vsnprintf(buf, sizeof(buf)-2, fmt, ap);
va_end(ap);
// codacy does not like strlen()
if ('\n' != buf[strnlen(buf, sizeof(buf) - 1) - 1]) {
(void)strlcat(buf, "\n", sizeof(buf));
}
if (0 >= write(gpsdata->gps_fd, buf, strnlen(buf, sizeof(buf)))) {
GPSD_LOG(LOG_ERROR, &context.errout,
"gps_query(), write failed: %s(%d)\n",
strerror(errno), errno);
return false;
}
GPSD_LOG(LOG_PROG, &context.errout, "gps_query(), wrote, %s\n", buf);
FD_ZERO(&rfds);
starttime = time(NULL);
for (;;) {
FD_CLR(gpsdata->gps_fd, &rfds);
GPSD_LOG(LOG_PROG, &context.errout, "waiting...\n");
tv.tv_sec = 2;
tv.tv_nsec = 0;
// (socket_t) to pacify codacy.
if (-1 == pselect((socket_t)gpsdata->gps_fd + 1, &rfds, NULL, NULL,
&tv, &oldset)) {
if (EINTR == errno ||
!FD_ISSET(gpsdata->gps_fd, &rfds)) {
continue;
}
GPSD_LOG(LOG_ERROR, &context.errout, "select %s(%d)\n",
strerror(errno), errno);
exit(EXIT_FAILURE);
}
GPSD_LOG(LOG_PROG, &context.errout, "reading...\n");
(void)gps_read(gpsdata, NULL, 0);
if (ERROR_SET & gpsdata->set) {
GPSD_LOG(LOG_ERROR, &context.errout, "error '%s'\n",
gpsdata->error);
return false;
}
if ((NON_ERROR == expect) ||
0 != (expect & gpsdata->set)) {
return true;
}
// else
if (0 < timeout &&
(time(NULL) - starttime > timeout)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"timed out after %d seconds\n",
timeout);
return false;
}
}
return false;
}
static void onsig(int sig)
{
// CWE-479: Signal Handler Use of a Non-reentrant Function
// See: The C Standard, 7.14.1.1, paragraph 5 [ISO/IEC 9899:2011]
// Can't log in a signal handler. Can't even call exit().
if (sig == SIGALRM) {
_exit(EXIT_FAILURE);
}
// else
_exit(EXIT_SUCCESS);
}
// full ID of the device for reports, including subtype
static char *gpsd_id(struct gps_device_t *session)
{
static char buf[128];
if (NULL == session ||
NULL == session->device_type ||
NULL == session->device_type->type_name) {
return "unknown,";
}
(void)strlcpy(buf, session->device_type->type_name, sizeof(buf));
if ('\0' != session->subtype[0]) {
(void)strlcat(buf, " ", sizeof(buf));
(void)strlcat(buf, session->subtype, sizeof(buf));
}
return (buf);
}
// recognize when we've achieved sync
static void ctlhook(struct gps_device_t *device UNUSED,
gps_mask_t changed UNUSED)
{
static int packet_counter = 0;
/*
* If it's NMEA, go back around enough times for the type probes to
* reveal any secret identity (like SiRF or UBX) the chip might have.
* If it's not, getting more packets might fetch subtype information.
*/
if (REDIRECT_SNIFF <= packet_counter++) {
hunting = false;
(void)alarm(0);
}
}
static void usage(void)
{
(void)printf("usage: gpsctl [OPTIONS] [device]\n\n"
#ifdef HAVE_GETOPT_LONG
" --binary Switch device to native binary mode.\n"
" --debug DEBUGLEVEL Set debug level to DEBUGLEVEL.\n"
" --direct Force direct access to the device.\n"
" --echo Echo specified control string with wrapper.\n"
" --help Show this help, then exit\n"
" --list List known device types and exit.\n"
" --nmea Switch device to NMEA mode.\n"
" --rate RATE Change receiver cyclte time to RATE.\n"
" --reset Force reset to default mode.\n"
#ifdef SHM_EXPORT_ENABLE
" --rmshm Remove the SHM export segment and exit.\n"
#endif // SHM_EXPORT_ENABLE
" --ship CONTROL Ship specified control string.\n"
" --speed SPEED Set device speed to SPEED.\n"
" --timeout TIMEOUT Set the timeout on packet recognition.\n"
" --type DEVTYPE Force the device type.\n"
" --version Show version, then exit\n"
#endif // HAVE_GETOPT_LONG
" -? Show this help, then exit\n"
" -b Switch device to native binary mode.\n"
" -c RATE Change receiver cyclte time to RATE.\n"
" -D DEBUGLEVEL Set debug level to DEBUGLEVEL.\n"
" -e Echo specified control string with wrapper.\n"
" -f Force direct access to the device.\n"
" -h Show this help, then exit\n"
" -l List known device types and exit.\n"
" -n Switch device to NMEA mode.\n"
#ifdef SHM_EXPORT_ENABLE
" -R Remove the SHM export segment and exit.\n"
#endif // SHM_EXPORT_ENABLE
" -r Force reset to default mode.\n"
" -s SPEED Set device speed to SPEED.\n"
" -t DEVTYPE Force the device type.\n"
" -T TIMEOUT Set the timeout on packet recognition.\n"
" -V Show version, then exit\n"
" -x CONTROL Ship specified control string.\n");
}
int main(int argc, char **argv)
{
static struct gps_device_t session; // zero this too
int ch, status;
char *device = NULL, *devtype = NULL;
char *speed = NULL, *ship = NULL, *rate = NULL;
bool to_binary = false, to_nmea = false, reset = false;
bool control_stdout = false;
bool lowlevel = false, echo = false;
struct gps_data_t gpsdata;
const struct gps_type_t *forcetype = NULL;
const struct gps_type_t **dp;
char cooked[BUFSIZ];
ssize_t cooklen = 0;
const char *optstring = "?bec:fhlnrs:t:x:D:RT:V";
#ifdef HAVE_GETOPT_LONG
int option_index = 0;
static struct option long_options[] = {
{"binary", no_argument, NULL, 'b'},
{"debug", required_argument, NULL, 'D'},
{"direct", no_argument, NULL, 'f'},
{"echo", no_argument, NULL, 'e'},
{"help", no_argument, NULL, 'h'},
{"list", no_argument, NULL, 'l'},
{"nmea", no_argument, NULL, 'n'},
{"rate", required_argument, NULL, 'c'},
#ifdef SHM_EXPORT_ENABLE
{"rmshm", required_argument, NULL, 'R'},
#endif
{"ship", required_argument, NULL, 'x'},
{"speed", required_argument, NULL, 's'},
{"timeout", required_argument, NULL, 'T'},
{"type", required_argument, NULL, 't'},
{"version", no_argument, NULL, 'V' },
{NULL, 0, NULL, 0},
};
#endif
// We need this before any logging happens (for report_mutex)
gps_context_init(&context, "gpsctl");
while (1) {
#ifdef HAVE_GETOPT_LONG
ch = getopt_long(argc, argv, optstring, long_options, &option_index);
#else
ch = getopt(argc, argv, optstring);
#endif
if (-1 == ch) {
break;
}
switch (ch) {
case 'b': // switch to vendor binary mode
to_binary = true;
break;
case 'c':
rate = optarg;
break;
case 'D': // set debugging level
debuglevel = atoi(optarg);
context.errout.debug = debuglevel;
gps_enable_debug(debuglevel, stderr);
break;
case 'e': // echo specified control string with wrapper
lowlevel = true;
control_stdout = true; // Prevent message going to stdout
echo = true;
break;
case 'f': // force direct access to the device
lowlevel = true;
break;
case 'l': // list known device types
for (dp = gpsd_drivers; *dp; dp++) {
if (NULL != (*dp)->mode_switcher) {
(void)fputs("-[bn]\t", stdout);
} else {
(void)fputc('\t', stdout);
}
if (NULL != (*dp)->speed_switcher) {
(void)fputs("-s\t", stdout);
} else {
(void)fputc('\t', stdout);
}
if (NULL != (*dp)->rate_switcher) {
(void)fputs("-c\t", stdout);
} else {
(void)fputc('\t', stdout);
}
if (NULL != (*dp)->control_send) {
(void)fputs("-x\t", stdout);
} else {
(void)fputc('\t', stdout);
}
(void)puts((*dp)->type_name);
}
exit(EXIT_SUCCESS);
case 'n': // switch to NMEA mode
to_nmea = true;
break;
#ifdef SHM_EXPORT_ENABLE
case 'R': // remove the SHM export segment
status = shmget(getenv("GPSD_SHM_KEY") ?
(key_t)strtol(getenv("GPSD_SHM_KEY"), NULL, 0) :
(key_t)GPSD_SHM_KEY, 0, 0);
if (-1 == status) {
GPSD_LOG(LOG_WARN, &context.errout,
"GPSD SHM segment does not exist.\n");
exit(1);
}
// else
status = shmctl(status, IPC_RMID, NULL);
if (-1 == status) {
GPSD_LOG(LOG_ERROR, &context.errout,
"shmctl failed, errno = %d (%s)\n",
errno, strerror(errno));
exit(1);
}
exit(0);
#endif // SHM_EXPORT_ENABLE
case 'r': // force-switch to default mode
reset = true;
lowlevel = false; // so we'll abort if the daemon is running
break;
case 's': // change output baud rate
speed = optarg;
break;
case 'T': // set the timeout on packet recognition
timeout = (unsigned)atoi(optarg);
explicit_timeout = true;
break;
case 't': // force the device type
devtype = optarg;
// experimental kluge
if (0 == strcmp(devtype, "u-blox")) {
timeout = 2;
}
break;
case 'x': // ship specified control string
ship = optarg;
if (0 >= (cooklen = hex_escapes(cooked, ship))) {
GPSD_LOG(LOG_ERROR, &context.errout,
"invalid escape string (error %zd)\n", cooklen);
exit(EXIT_FAILURE);
} else {
char buf[BUFSIZ];
GPSD_LOG(LOG_PROG, &context.errout,
"cooked string to ship: >%s<\n",
gps_visibilize(buf, sizeof(buf), cooked, cooklen));
}
break;
case 'V':
(void)fprintf(stderr, "%s: version %s (revision %s)\n",
argv[0], VERSION, REVISION);
exit(EXIT_SUCCESS);
case '?':
FALLTHROUGH
case 'h':
usage();
exit(EXIT_SUCCESS);
default:
usage();
exit(EXIT_FAILURE);
}
}
if (optind < argc) {
device = argv[optind];
}
if (NULL != devtype) {
int matchcount = 0;
for (dp = gpsd_drivers; *dp; dp++) {
if (NULL != strstr((*dp)->type_name, devtype)) {
forcetype = *dp;
matchcount++;
}
}
if (0 == matchcount) {
GPSD_LOG(LOG_ERROR, &context.errout,
"no driver type name matches '%s'.\n", devtype);
} else if (1 == matchcount) {
assert(NULL != forcetype);
GPSD_LOG( LOG_PROG,&context.errout,
"%s driver selected.\n", forcetype->type_name);
} else {
forcetype = NULL;
GPSD_LOG(LOG_ERROR, &context.errout,
"%d driver type names match '%s'.\n",
matchcount, devtype);
}
}
if (1 < ((int)to_nmea + (int)to_binary + (int)reset)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"make up your mind, would you?\n");
exit(EXIT_SUCCESS);
}
(void)signal(SIGINT, onsig);
(void)signal(SIGTERM, onsig);
(void)signal(SIGQUIT, onsig);
if (!lowlevel) {
int i, devcount;
// Try to open the stream to gpsd.
if (0 != gps_open(NULL, NULL, &gpsdata)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"no gpsd running or network error: %s.\n",
gps_errstr(errno));
lowlevel = true;
}
if (!explicit_timeout) {
timeout = HIGH_LEVEL_TIMEOUT;
}
// what devices have we available?
if (!gps_query(&gpsdata, DEVICELIST_SET, (int)timeout,
"?DEVICES;\r\n")) {
GPSD_LOG(LOG_ERROR, &context.errout,
"no DEVICES response received.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
if (0 == gpsdata.devices.ndevices) {
GPSD_LOG(LOG_ERROR, &context.errout, "no devices connected.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
// else
if (1 < gpsdata.devices.ndevices &&
NULL == device) {
GPSD_LOG(LOG_ERROR, &context.errout,
"multiple devices and no device specified.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
GPSD_LOG(LOG_PROG, &context.errout, "%d device(s) found.\n",
gpsdata.devices.ndevices);
// try to mine the devicelist return for the data we want
if (1 == gpsdata.devices.ndevices &&
NULL == device) {
device = gpsdata.dev.path;
i = 0;
} else {
assert(NULL != device);
for (i = 0; i < gpsdata.devices.ndevices; i++) {
if (0 == strcmp(device, gpsdata.devices.list[i].path)) {
break;
}
}
if (i >= gpsdata.devices.ndevices) {
GPSD_LOG(LOG_ERROR, &context.errout,
"specified device not found in device list.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
}
gpsdata.dev = gpsdata.devices.list[i];
devcount = gpsdata.devices.ndevices;
// if the device has not identified, watch it until it does so
if ('\0' == gpsdata.dev.driver[0]) {
if (-1 == gps_stream(&gpsdata, WATCH_ENABLE|WATCH_JSON, NULL)) {
GPSD_LOG(LOG_ERROR, &context.errout, "stream set failed.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
while (0 < devcount) {
// Wait for input data
if (!gps_waiting(&gpsdata, timeout * 1000000)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"timed out waiting for device\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
errno = 0;
if (-1 == gps_read(&gpsdata, NULL, 0)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"data read failed.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
}
if (gpsdata.set & DEVICE_SET) {
--devcount;
assert('\0' != gpsdata.dev.path[0] &&
'\0' != gpsdata.dev.driver[0]);
if (0 == strcmp(gpsdata.dev.path, device)) {
goto matching_device_seen;
}
}
}
GPSD_LOG(LOG_ERROR, &context.errout, "data read failed.\n");
(void)gps_close(&gpsdata);
exit(EXIT_FAILURE);
matching_device_seen:;
}
// sanity check
if ('\0' == gpsdata.dev.driver[0]) {
GPSD_LOG(LOG_SHOUT, &context.errout, "%s can't be identified.\n",
gpsdata.dev.path);
(void)gps_close(&gpsdata);
exit(EXIT_SUCCESS);
}
// if no control operation was specified, just ID the device
if (NULL == rate &&
NULL == ship &&
NULL == speed &&
!to_nmea &&
!to_binary &&
!reset) {
(void)printf("%s identified as a %s",
gpsdata.dev.path, gpsdata.dev.driver);
if ('\0' != gpsdata.dev.subtype[0]) {
(void)fputc(' ', stdout);
(void)fputs(gpsdata.dev.subtype, stdout);
}
if (0 < gpsdata.dev.baudrate) {
(void)printf(" at %u baud", gpsdata.dev.baudrate);
}
(void)puts(".");
}
status = 0;
if (reset) {
GPSD_LOG(LOG_PROG, &context.errout,
"cannot reset with gpsd running.\n");
exit(EXIT_SUCCESS);
}
/*
* We used to wait on DEVICE_SET here. That doesn't work
* anymore because when the demon generates its response it
* sets the mode bit in the response from the current packet
* type, which may not have changed (probably will not have
* changed) even though the command to switch modes has been
* sent and will shortly take effect.
*/
if (to_nmea) {
if (!gps_query(&gpsdata, NON_ERROR, (int)timeout,
"?DEVICE={\"path\":\"%s\",\"native\":0}\r\n",
device)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s mode change to NMEA failed\n",
gpsdata.dev.path);
status = 1;
} else {
GPSD_LOG(LOG_PROG, &context.errout,
"%s mode change succeeded\n", gpsdata.dev.path);
}
} else if (to_binary) {
if (!gps_query(&gpsdata, NON_ERROR, (int)timeout,
"?DEVICE={\"path\":\"%s\",\"native\":1}\r\n",
device)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s mode change to native mode failed\n",
gpsdata.dev.path);
status = 1;
} else
GPSD_LOG(LOG_PROG, &context.errout,
"%s mode change succeeded\n",
gpsdata.dev.path);
}
if (NULL != ship) {
char buf[BUFSIZ];
(void)gps_hexdump(buf, sizeof(buf), (unsigned char *)cooked,
cooklen);
(void)gps_query(&gpsdata,
DEVICE_SET, (int)timeout,
"?DEVICE={\"path\":\"%s\",\"hexdata\":\"%s\"}\r\n",
device, buf);
// wait for response?
}
if (NULL != speed) {
char parity = 'N';
char stopbits = '1';
if (NULL == strchr(speed, ':')) {
(void)gps_query(&gpsdata,
DEVICE_SET, (int)timeout,
"?DEVICE={\"path\":\"%s\",\"bps\":%s}\r\n",
device, speed);
} else {
char *modespec = strchr(speed, ':');
status = 0;
if (NULL != modespec) {
*modespec = '\0';
if (NULL == strchr("78", *++modespec)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"No support for that word length.\n");
status = 1;
}
parity = *++modespec;
if (NULL == strchr("NOE", parity)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"What parity is '%c'?\n", parity);
status = 1;
}
stopbits = *++modespec;
if (NULL == strchr("12", stopbits)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"Stop bits must be 1 or 2.\n");
status = 1;
}
}
if (0 == status)
(void)gps_query(&gpsdata,
DEVICE_SET, (int)timeout,
"?DEVICE={\"path\":\"%s\",\"bps\":%s,"
"\"parity\":\"%c\",\"stopbits\":%c}\r\n",
device, speed, parity, stopbits);
}
if (atoi(speed) != (int)gpsdata.dev.baudrate) {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s driver won't support %s%c%c\n",
gpsdata.dev.path,
speed, parity, stopbits);
status = 1;
} else {
GPSD_LOG(LOG_PROG, &context.errout,
"%s change to %s%c%c succeeded\n",
gpsdata.dev.path,
speed, parity, stopbits);
}
}
if (NULL != rate) {
(void)gps_query(&gpsdata,
DEVICE_SET, (int)timeout,
"?DEVICE={\"path\":\"%s\",\"cycle\":%s}\r\n",
device, rate);
}
(void)gps_close(&gpsdata);
exit(status);
} else if (reset) {
// hard reset will go through lower-level operations
// FIXME: missing speeds, should come from a header.
const int speeds[] = {4800, 9600, 19200, 38400, 57600, 115200, 230400,
460800, 921600};
static struct gps_device_t session; // zero this too
int i;
if (NULL == device ||
NULL == forcetype) {
GPSD_LOG(LOG_ERROR, &context.errout,
"device and type must be specified for the "
"reset operation.\n");
exit(EXIT_FAILURE);
}
context.errout.debug = debuglevel;
session.context = &context;
gpsd_tty_init(&session);
(void)strlcpy(session.gpsdata.dev.path, device,
sizeof(session.gpsdata.dev.path));
session.device_type = forcetype;
(void)gpsd_open(&session);
(void)gpsd_set_raw(&session);
(void)session.device_type->speed_switcher(&session, 4800, 'N', 1);
(void)tcdrain(session.gpsdata.gps_fd);
for(i = 0; i < (int)(sizeof(speeds) / sizeof(speeds[0])); i++) {
(void)gpsd_set_speed(&session, speeds[i], 'N', 1);
(void)session.device_type->speed_switcher(&session, 4800, 'N', 1);
(void)tcdrain(session.gpsdata.gps_fd);
}
gpsd_set_speed(&session, 4800, 'N', 1);
for (i = 0; i < 3; i++) {
if (session.device_type->mode_switcher) {
session.device_type->mode_switcher(&session, MODE_NMEA);
}
}
gpsd_wrap(&session);
exit(EXIT_SUCCESS);
}
// else
// lowlevel, or access to the daemon failed, use the low-level facilities
fd_set all_fds;
fd_set rfds;
/*
* Unless the user explicitly requested it, always run to end of
* hunt rather than timing out. Otherwise we can easily get messages
* that spuriously look like failure at high baud rates.
*/
gps_context_init(&context, "gpsctl");
context.errout.debug = debuglevel;
session.context = &context; // in case gps_init isn't called
if (echo) {
context.readonly = true;
}
if (0 < timeout) {
(void)alarm(timeout);
(void)signal(SIGALRM, onsig);
}
/*
* Unless the user has forced a type and only wants to see the
* string (not send it) we now need to try to open the device
* and find out what is actually there.
*/
if (NULL == forcetype ||
!echo) {
socket_t maxfd = 0;
int activated = -1;
if (NULL == device) {
GPSD_LOG(LOG_ERROR, &context.errout,
"device must be specified for low-level access.\n");
exit(EXIT_FAILURE);
}
gpsd_init(&session, &context, device);
activated = gpsd_activate(&session, O_PROBEONLY);
if (0 > activated) {
if (PLACEHOLDING_FD == activated) {
(void)printf("%s identified as a %s.\n",
device, gpsd_id(&session));
exit(EXIT_SUCCESS);
}
GPSD_LOG(LOG_ERROR, &context.errout,
"initial GPS device %s open failed\n",
device);
exit(EXIT_FAILURE);
}
GPSD_LOG(LOG_INF, &context.errout,
"device %s activated\n", session.gpsdata.dev.path);
FD_SET(session.gpsdata.gps_fd, &all_fds);
if (session.gpsdata.gps_fd > maxfd) {
maxfd = session.gpsdata.gps_fd;
}
// initialize the GPS context's time fields
gpsd_time_init(&context, time(NULL));
// grab packets until we time out, get sync, or fail sync
for (hunting = true; hunting; ) {
fd_set efds;
timespec_t ts_timeout = {2, 0}; // timeout for pselect()
switch(gpsd_await_data(&rfds, &efds, maxfd, &all_fds,
&context.errout, ts_timeout)) {
case AWAIT_GOT_INPUT:
FALLTHROUGH
case AWAIT_TIMEOUT:
break;
case AWAIT_NOT_READY:
// no recovery from bad fd is possible
if (FD_ISSET(session.gpsdata.gps_fd, &efds)) {
exit(EXIT_FAILURE);
}
continue;
case AWAIT_FAILED:
exit(EXIT_FAILURE);
}
switch(gpsd_multipoll(FD_ISSET(session.gpsdata.gps_fd, &rfds),
&session, ctlhook, 0)) {
case DEVICE_READY:
FD_SET(session.gpsdata.gps_fd, &all_fds);
break;
case DEVICE_UNREADY:
FD_CLR(session.gpsdata.gps_fd, &all_fds);
break;
case DEVICE_ERROR:
// this is where a failure to sync lands
GPSD_LOG(LOG_WARN, &context.errout,
"device error, bailing out.\n");
exit(EXIT_FAILURE);
case DEVICE_EOF:
GPSD_LOG(LOG_WARN, &context.errout,
"device signed off, bailing out.\n");
exit(EXIT_SUCCESS);
default:
break;
}
}
GPSD_LOG(LOG_PROG, &context.errout,
"%s looks like a %s at %d.\n",
device, gpsd_id(&session),
session.gpsdata.dev.baudrate);
if (NULL != forcetype &&
0 != strcmp("NMEA0183", session.device_type->type_name) &&
0 != strcmp(forcetype->type_name,
session.device_type->type_name)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"'%s' doesn't match non-generic type '%s' "
"of selected device.\n",
forcetype->type_name,
session.device_type->type_name);
}
}
if(!control_stdout) {
(void)printf("%s identified as a %s at %u baud.\n",
device, gpsd_id(&session),
session.gpsdata.dev.baudrate);
}
// if no control operation was specified, we're done
if (NULL == ship &&
NULL == speed &&
!to_nmea &&
!to_binary) {
exit(EXIT_SUCCESS);
}
// maybe user wants to see the packet rather than send it
if (echo) {
session.gpsdata.gps_fd = fileno(stdout);
}
// control op specified; maybe we forced the type
if (NULL != forcetype) {
(void)gpsd_switch_driver(&session, forcetype->type_name);
}
// now perform the actual control function
status = 0;
if (to_nmea ||
to_binary) {
bool write_enable = context.readonly;
context.readonly = false;
if (NULL == session.device_type->mode_switcher) {
GPSD_LOG(LOG_SHOUT, &context.errout,
"%s devices have no mode switch.\n",
session.device_type->type_name);
status = 1;
} else {
int target_mode = to_nmea ? MODE_NMEA : MODE_BINARY;
GPSD_LOG(LOG_SHOUT, &context.errout,
"switching to mode %s.\n",
to_nmea ? "NMEA" : "BINARY");
session.device_type->mode_switcher(&session, target_mode);
settle(&session);
}
context.readonly = write_enable;
}
if (speed) {
char parity = echo ? 'N': session.gpsdata.dev.parity;
int stopbits = echo ? 1 : session.gpsdata.dev.stopbits;
char *modespec;
modespec = strchr(speed, ':');
status = 0;
if (NULL != modespec) {
*modespec = '\0';
if (NULL == strchr("78", *++modespec)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"No support for that word lengths.\n");
status = 1;
}
parity = *++modespec;
if (NULL == strchr("NOE", parity)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"What parity is '%c'?\n", parity);
status = 1;
}
stopbits = *++modespec;
if (NULL == strchr("12", parity)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"Stop bits must be 1 or 2.\n");
status = 1;
}
stopbits = (int)(stopbits-'0');
}
if (0 == status) {
if (NULL == session.device_type->speed_switcher) {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s devices have no speed switch.\n",
session.device_type->type_name);
status = 1;
} else if (session.device_type->speed_switcher(&session,
(speed_t)atoi(speed),
parity,
stopbits)) {
settle(&session);
GPSD_LOG(LOG_PROG, &context.errout,
"%s change to %s%c%d succeeded\n",
session.gpsdata.dev.path,
speed, parity, stopbits);
} else {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s driver won't support %s%c%d.\n",
session.gpsdata.dev.path,
speed, parity, stopbits);
status = 1;
}
}
}
if (rate) {
bool write_enable = context.readonly;
context.readonly = false;
if (NULL == session.device_type->rate_switcher) {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s devices have no rate switcher.\n",
session.device_type->type_name);
status = 1;
} else {
double rate_dbl = strtod(rate, NULL);
if (!session.device_type->rate_switcher(&session, rate_dbl)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"rate switch failed.\n");
status = 1;
}
settle(&session);
}
context.readonly = write_enable;
}
if (ship) {
bool write_enable = context.readonly;
context.readonly = false;
if (NULL == session.device_type->control_send) {
GPSD_LOG(LOG_ERROR, &context.errout,
"%s devices have no control sender.\n",
session.device_type->type_name);
status = 1;
} else {
if (-1 == session.device_type->control_send(&session,
cooked,
(size_t)cooklen)) {
GPSD_LOG(LOG_ERROR, &context.errout,
"control transmission failed.\n");
status = 1;
}
settle(&session);
}
context.readonly = write_enable;
}
exit(status);
}
// end
// vim: set expandtab shiftwidth=4
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。