Browse Source

Imported Upstream version 3.5

master
Bernd Zeimetz 8 years ago
parent
commit
e303d0aad5
53 changed files with 2444 additions and 527 deletions
  1. +9
    -0
      NEWS
  2. +47
    -30
      SConstruct
  3. +9
    -0
      TODO
  4. +25
    -1
      build.txt
  5. +23
    -0
      control
  6. +5
    -0
      devtools/README
  7. +6
    -1
      devtools/gpsd-debian-regressions.sh
  8. +201
    -0
      devtools/ppstest.c
  9. +48
    -42
      driver_aivdm.c
  10. +104
    -35
      driver_nmea.c
  11. +3
    -2
      gps.h
  12. +1
    -0
      gps/misc.py
  13. +39
    -2
      gpscap.ini
  14. +1
    -1
      gpsctl.1
  15. +40
    -7
      gpsctl.c
  16. +6
    -4
      gpsctl.xml
  17. +18
    -2
      gpsd.8
  18. +123
    -41
      gpsd.c
  19. +37
    -10
      gpsd.h-tail
  20. +11
    -22
      gpsd.php
  21. +11
    -22
      gpsd.php.in
  22. +2
    -0
      gpsd.rules
  23. +14
    -6
      gpsd.xml
  24. +123
    -18
      gpsd_json.5
  25. +90
    -2
      gpsd_json.xml
  26. +6
    -0
      gpsdecode.c
  27. +5
    -0
      gpsutils.c
  28. +1
    -1
      libgps.h
  29. +2
    -5
      libgpsd_core.c
  30. +6
    -8
      libgpsmm.3
  31. +5
    -9
      libgpsmm.xml
  32. +87
    -40
      ntpshm.c
  33. +2
    -1
      packaging/rpm/gpsd.spec
  34. +1
    -0
      packaging/rpm/gpsd.spec.in
  35. +9
    -0
      packet.c
  36. +1
    -0
      packet_names.h
  37. +1
    -0
      packet_states.h
  38. +0
    -4
      pps_pin.h
  39. +1
    -1
      revision.h
  40. +11
    -13
      serial.c
  41. +6
    -6
      subframe.c
  42. +1
    -0
      systemd/gpsd.socket
  43. +156
    -0
      test/daemon/GPSmap-76S.log
  44. +165
    -0
      test/daemon/GPSmap-76S.log.chk
  45. +15
    -15
      test/daemon/italk-binary.log.chk
  46. +85
    -0
      test/daemon/polarx2.log
  47. +93
    -0
      test/daemon/polarx2.log.chk
  48. +248
    -0
      test/daemon/sounder.log
  49. +366
    -0
      test/daemon/sounder.log.chk
  50. +2
    -2
      test/daemon/uBlox-aek-4t.log.chk
  51. +41
    -41
      test/daemon/uBlox-lea-4t.log.chk
  52. +1
    -2
      test/sample.aivdm
  53. +131
    -131
      test/sample.rtcm2.chk

+ 9
- 0
NEWS View File

@@ -1,3 +1,12 @@
* Fri 13 Apr 2012 Eric S. Raymond <esr@snark.thyrsus.com> - 3.5
Use pselect when it's available to cut down on wakeups and improve
signal handling. New {PPS} message exporting clock drift. The AIVDM
driver now handles up to 16 interleaved 24A and 24B pair-halves.
The NMEA driver interprets depth-sounder returns from SDDBT and
reports them as negative altitudes. The pps-pin option is gone, the
PPS code now just accepts any handshake pin. A bug that sometimes
caused RTCM packets to be dropped rather than relayed is fixed.

* Thu 12 Jan 2012 Eric S. Raymond <esr@snark.thyrsus.com> - 3.4
Don't barf when chrpath is not available, fall back to static linking;
helps people not running Linux.


+ 47
- 30
SConstruct View File

@@ -19,7 +19,7 @@
# * Out-of-directory builds: see http://www.scons.org/wiki/UsingBuildDir

# Release identification begins here
gpsd_version = "3.4"
gpsd_version = "3.5"

# library version
libgps_version_current = 20
@@ -167,7 +167,6 @@ nonboolopts = (
("limited_max_devices", 0, "maximum allowed devices"),
("fixed_port_speed", 0, "fixed serial port speed"),
("fixed_stop_bits", 0, "fixed serial port stop bits"),
("pps_pin", "DCD", "pin to expect PPS pulses on"),
("target", "", "cross-development target"),
("sysroot", "", "cross-development system root"),
)
@@ -459,6 +458,14 @@ else:
confdefs.append("/* #undef HAVE_LIBRT */\n")
rtlibs = []

if config.CheckLib('libcap'):
confdefs.append("#define HAVE_LIBCAP 1\n")
# System library - no special flags
rtlibs = ["-lcap"]
else:
confdefs.append("/* #undef HAVE_LIBCAP */\n")
rtlibs = []

if env['dbus_export'] and config.CheckPKG('dbus-1'):
confdefs.append("#define HAVE_DBUS 1\n")
dbus_libs = pkg_config('dbus-1')
@@ -519,6 +526,10 @@ for (key,help) in keys:
else:
confdefs.append("#define %s \"%s\"\n" % (key.upper(), value))

if config.CheckFunc("pselect"):
confdefs.append("/* #undef COMPAT_SELECT */\n")
else:
confdefs.append("#define COMPAT_SELECT\n")

confdefs.append('''
/* will not handle pre-Intel Apples that can run big-endian */
@@ -761,7 +772,7 @@ compiled_gpslib = Library(env=env,
target="gps",
sources=libgps_sources,
version=libgps_version,
parse_flags= ["-lm"] + dbus_libs)
parse_flags=dbus_libs)
env.Clean(compiled_gpslib, "gps_maskdump.c")

compiled_gpsdlib = Library(env=env,
@@ -783,7 +794,7 @@ if qt_env:
# infamous "Two environments with different actions were specified
# for the same target" error.
for src in libgps_sources:
if src in ("gpsutils.c", "libgps_sock.c"):
if src not in ('ais_json.c','json.c','libgps_json.c','rtcm2_json.c','shared_json.c'):
compile_with = qt_env['CXX']
compile_flags = qt_flags
else:
@@ -798,7 +809,7 @@ if qt_env:

# The libraries have dependencies on system libraries

gpslibs = ["-lgps"]
gpslibs = ["-lgps", "-lm"]
gpsdlibs = ["-lgpsd"] + usblibs + bluezlibs + gpslibs

# Source groups
@@ -850,7 +861,7 @@ gpsdctl = env.Program('gpsdctl', ['gpsdctl.c'], parse_flags=gpslibs)
env.Depends(gpsdctl, compiled_gpslib)

gpsmon = env.Program('gpsmon', gpsmon_sources,
parse_flags=gpsdlibs + ncurseslibs)
parse_flags=gpsdlibs + ncurseslibs + ['-lm'])
env.Depends(gpsmon, [compiled_gpsdlib, compiled_gpslib])

gpspipe = env.Program('gpspipe', ['gpspipe.c'], parse_flags=gpslibs)
@@ -912,11 +923,11 @@ else:
}

python_env = env.Clone()
vars = sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO', 'INCLUDEPY')
vars = sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO', 'INCLUDEPY', 'LDFLAGS')
for i in range(len(vars)):
if vars[i] is None:
vars[i] = ""
(cc, cxx, opt, basecflags, ccshared, ldshared, so_ext, includepy) = vars
vars[i] = []
(cc, cxx, opt, basecflags, ccshared, ldshared, so_ext, includepy, ldflags) = vars
# in case CC/CXX was set to the scan-build wrapper,
# ensure that we build the python modules with scan-build, too
if env['CC'] is None or env['CC'].find('scan-build') < 0:
@@ -928,12 +939,18 @@ else:
else:
python_env['CXX'] = ' '.join([env['CXX']] + cxx.split()[1:])

python_env['SHLINKFLAGS'] = []
python_env['SHLINK'] = ldshared
python_env['SHLIBPREFIX']=""
python_env['SHLIBSUFFIX']=so_ext
python_env['CPPPATH'] =[includepy]
python_env['CPPFLAGS']=basecflags + " " + opt
ldshared=ldshared.replace('-fPIE', '')
ldshared=ldshared.replace('-pie', '')
python_env.Replace(SHLINKFLAGS=[],
LDFLAGS=ldflags,
LINK = ldshared,
SHLIBPREFIX="",
SHLIBSUFFIX=so_ext,
CPPPATH=[includepy],
CPPFLAGS=opt,
CFLAGS=basecflags,
CXXFLAGS=basecflags)

python_objects={}
python_compiled_libs = {}
for ext, sources in python_extensions.iteritems():
@@ -948,7 +965,6 @@ else:
)
python_compiled_libs[ext] = python_env.SharedLibrary(ext, python_objects[ext])
python_built_extensions = python_compiled_libs.values()

python_egg_info_source = """Metadata-Version: 1.0
Name: gps
Version: %s
@@ -999,17 +1015,8 @@ else:
revision='#define REVISION "%s"\n' %(rev.strip(),)
env.Textfile(target="revision.h", source=[revision])

# generate pps_pin.h
pps_pin = env['pps_pin']
ppsh = '/* generated by scons from the pps_pin option - do not hand-hack */\n'
ppsh += '#define PPS_LINE_NAME "%s"\n' % pps_pin
tioc_map = {"DCD": "CAR"}
ppsh += '#define PPS_LINE_TIOC TIOCM_%s\n' % tioc_map.get(pps_pin, pps_pin)
ppsh += "/* end */\n"
env.NoClean(env.Textfile(target="pps_pin.h", source=[ppsh]))

generated_sources = ['packet_names.h', 'timebase.h', 'gpsd.h', "ais_json.i",
'gps_maskdump.c', 'revision.h', 'gpsd.php', 'pps_pin.h']
'gps_maskdump.c', 'revision.h', 'gpsd.php']

# leapseconds.cache is a local cache for information on leapseconds issued
# by the U.S. Naval observatory. It gets kept in the repository so we can
@@ -1154,7 +1161,7 @@ else:
python_module_dir = python_lib_dir + os.sep + 'gps'
python_extensions_install = python_env.Install( DESTDIR + python_module_dir,
python_built_extensions)
if not env['debug'] or env['profiling']:
if not env['debug'] and not env['profiling'] and env['strip']:
python_env.AddPostAction(python_extensions_install, '$STRIP $TARGET')

python_modules_install = python_env.Install( DESTDIR + python_module_dir,
@@ -1320,7 +1327,7 @@ rtcm_regress = Utility('rtcm-regress', [gpsdecode], [
# Rebuild the RTCM regression tests.
Utility('rtcm-makeregress', [gpsdecode], [
'for f in $SRCDIR/test/*.rtcm2; do '
'$SRCDIR/gpsdecode -j < ${f} > ${f}.chk; '
'$SRCDIR/gpsdecode -j <$${f} >$${f}.chk; '
'done'
])

@@ -1517,7 +1524,7 @@ if env['python']:
# GPS ad libitum. All is well when you get fix reports each time a GPS
# is plugged in.

Utility('udev-install', '', [
Utility('udev-install', 'install', [
'mkdir -p ' + DESTDIR + '/lib/udev/rules.d',
'cp $SRCDIR/gpsd.rules ' + DESTDIR + '/lib/udev/rules.d/25-gpsd.rules',
'cp $SRCDIR/gpsd.hotplug ' + DESTDIR + '/lib/udev/',
@@ -1556,7 +1563,7 @@ if os.path.exists("gpsd.c") and os.path.exists(".gitignore"):
env.Clean(tarball, ["gpsd-${VERSION}.tar.gz", "packaging/rpm/gpsd.spec"])

# Make RPM from the specfile in packaging
Utility('dist-rpm', tarball, 'rpmbuild -ta $SOURCE')
Utility('dist-rpm', tarball, 'rpmbuild -ta gpsd-${VERSION}.tar.gz')

# Make sure build-from-tarball works.
testbuild = Utility('testbuild', [tarball], [
@@ -1606,6 +1613,16 @@ if os.path.exists("gpsd.c") and os.path.exists(".gitignore"):
upload_tags,
upload_web])

# Experimental release mechanics using shipper
# This will ship a freecode metadata update
ship_release = Utility("ship_release",
[tarball],
['shipper -u -m --exclude "login.ibiblio.org:/public/html/catb/esr/"'])
env.Alias("ship", [releaseprep,
ship_release,
upload_tags])


# The following sets edit modes for GNU EMACS
# Local Variables:
# mode:python


+ 9
- 0
TODO View File

@@ -32,6 +32,11 @@ packet aggregation issue.

*** Driver issues

**** There are architecture issues in the binary drivers.

Some fail regression tests on non-x86 architectures (not SiRF or
NMEA, thankfully). Bernd Zeimetz has the check logs.

**** gpsctl -b should work on UBX, but does not.

Presently this means there's no way to kick a UBX into returning
@@ -50,6 +55,10 @@ This one is mine and Kurt Schwehr's. Support is currently nearly
complete; the only missing cases are a handful of IMO 236 and IMO 289
message 6 and 8 subtypes.

**** Addressed case of AIS Types 25 and 26 is not handled.

We'd need machinery to shift a byte array 30 bits left...

** Ports

*** Windows port


+ 25
- 1
build.txt View File

@@ -5,6 +5,15 @@ guidance on how to cross-build the package.

(This file is marked up in asciidoc.)

== Quick start ==

Under Linux, assuming you have all your build prerequisites in place,
this line will do:

scons && scons testregress && sudo scons udev-install

If you get any errors, you need to read the detailed instructions that follow.

== Check your build prerequisites ==

Necessary components for any build:
@@ -45,6 +54,12 @@ some code generators in Python), it is not required to run the service
daemon. In particular, you can cross-compile onto an embedded system
without having to take Python with you.

You will need both basic Python and (if your package system makes the
distinction) the Python development package used for building C
extensions. Usually these are called "python" and "python-dev". You
will know you are missing the latter if your compilation fails
because of a missing Python.h.

=== Scons ===

You will need scons version 2.0.1 or later to build the code. The
@@ -74,6 +89,7 @@ various additional capabilities and extensions:
|============================================================================
|C++ compiler | allows building libgpsmm C++ wrapper for client library
|Qt 4.53+ | allows building libQgpsmm C++ wrapper for client library
|libcap | Capabilities library, allows 1PPS support under Linux
|============================================================================

If you have libusb-1.0.0 or later, the GPSD build will autodetect
@@ -195,7 +211,7 @@ footprint. "scons --help" will tell the story; look under "Local Options"
and consult the source code if in doubt.

Here are a few of the more important feature switches. Each description
begins with the default for the xwitch.
begins with the default for the switch.

pps=yes: for small embedded systems and those without threading,
it is possible to build gpsd without thread support if you build
@@ -212,6 +228,14 @@ client library to be available on all the Qt supported platforms.
Please see http://qt.nokia.com/doc/4.6/supported-platforms.html for a
status of Qt supported platforms as of version 4.6.

== Port and toolchain testing ==

'scons testregress' will run a comprehensive regression-test suite.
You should do this, at minimum, every time you build from source
on a new machine type. GPSD does enough bit-twiddling and floating
point that it is very sensitive to toolchain problems; you'll want to
be sure those aren't going to bite you in production.

== Reverting to a clean state ==

The scons equivalent of 'make clean' is 'scons -c'. This will revert


+ 23
- 0
control View File

@@ -0,0 +1,23 @@
# This is not a real Debian control file
# It's project metadata for the shipper tool

Package: gpsd

Description: monitoring daemon for GPSes, AIS radios, and other navigation aids
gpsd is a userland daemon acting as a translator between GPS and
AIS receivers and their clients. gpsd listens on port 2947 for clients
requesting position/time/velocity information. The receivers are
expected to generate position information in a well-known format -- as
NMEA-0183 sentences, SiRF binary, Rockwell binary, Garmin binary
format, or other vendor binary protocols. gpsd takes this
information from the GPS and translates it into JSON objects in a uniform
and well-documented format that easier for clients to understand. The
distribution includes sample clients, application interface libraries,
and test/profiling tools.

XBS-Destinations: ~, savannah, freecode
XBS-Web-Directory: www

XBS-Project-Tag-List: Communications, Scientific/Engineering, Geographical



+ 5
- 0
devtools/README View File

@@ -63,6 +63,11 @@ list of failed regression tests, sorted by architecture.
Extract pure NMEA from an emailed gpsd error log. The output can be fed
to gpsfake.

== ppstest ==

Simple program to check for PPS coming from a serial or USB device.
Compile with "make ppstest". See the header comment for instructions.

== regress-builder ==

This script runs an exhaustive test on combinations of compilation options,


+ 6
- 1
devtools/gpsd-debian-regressions.sh View File

@@ -5,6 +5,11 @@

set -e

logs='last'
if [ -n "$1" ]; then
logs=$1
fi

if [ ! -x /usr/bin/getbuildlog ]; then
echo 'Please install the devscripts package!'
exit 1
@@ -14,7 +19,7 @@ TMPDIR=`mktemp -d`
OLDPWD=`pwd`

cd ${TMPDIR}
getbuildlog gpsd last || true
getbuildlog gpsd $logs || true
grep -- '--- test' * | sed 's,^gpsd_[^_]*_\([^.]*\).*\./test/\([^.]*\).*,\1 \2,' | sort -u
cd ${OLDPWD}
rm -rf ${TMPDIR}


+ 201
- 0
devtools/ppstest.c View File

@@ -0,0 +1,201 @@
#include <termios.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

/*
* Test to see if TIOCMGET/TIOCMIWAIT can be made to work
* Call with the serial device name argument, and possibly -p or -w options
*
* Based on code fond here:
* http://tech.groups.yahoo.com/group/ts-7000/message/803
*/
int main(int argc, char **argv)
{
int fd;
struct termios newtio;
unsigned char rx[132];
enum {dump, poll, wait} mode = dump;
int option;
char *device;

struct {char *name; int value;} pin_map[] = {
{"CTS", TIOCM_CTS}, /* Clear to send */
{"CAR", TIOCM_CAR}, /* Carrier detect */
{"DCD", TIOCM_CD}, /* Carrier detect (synonym - default) */
{"RI", TIOCM_RI}, /* Ring Indicator */
{"RNG", TIOCM_RNG}, /* Ring Indicator (synonym) */
{"DSR", TIOCM_DSR}, /* Data Set Ready */
{NULL, 0},
}, *pp = &pin_map[2];

while ((option = getopt(argc, argv, "dl:pw")) != -1) {
switch (option) {
case 'd': /* dump data from the TTY */
mode = dump;
break;
case 'p': /* poll for PPS */
mode = poll;
break;
case 'w': /* wait for PPS state change */
mode = wait;
break;
case 'l': /* set the handshake line to use by name */
for (pp = pin_map; pp->name != NULL; pp++)
if (strcmp(pp->name, optarg) == 0) {
break;
}
if (pp->name == NULL) {
(void)fprintf(stderr,
"Didn't recognize %s as a handshake.\n",
optarg);
exit(1);
}
break;
case '?':
case 'h':
(void)fprintf(stderr, "usage: ppstest [-p] [-w] [-l CTS|CAR|RI|RNG|DSR] device\n");
exit(0);
}
}
device = argv[optind];

// try to open the serial port
fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
// how'd that go?
if (fd < 0) {
// not so good
perror("Unable to open device /dev/ttyAM0\n");
return 1;
}
fprintf(stderr, "Successfully opened serial device %s\n", device);

/* initialize the serial port */
memset(&newtio, '\0', sizeof(newtio));
newtio.c_cflag = CS8 | CREAD | CRTSCTS;
tcflush(fd, TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

// Figure out which mode we are operating in, based on the command
// line argument.
//
// Operating Modes:
// mode = dump - Dump out serial data from port
// mode = wait - Use TIOCMIWAIT to detect changes on the line -
// mode = poll - Use TIOCMGET to detect changes on the line via polling

// Select operation based on mode
switch (mode)
{
case dump:
// just dump out any characters arriving on the serial port
fprintf(stderr, "Testing Serial Interface. Dumping data from %s\n", device);
int readCnt;
while (1) {
while (read(fd, rx, 132) > 0) {
rx[131] = 0;
fprintf(stderr, "%s", rx);
}
sleep(1);
}
break;

case wait:
// wait for transition to be reported via interrupt
(void)fprintf(stderr,
"Testing TIOCMIWAIT. Waiting for %s on %s\n",
pp->name, device);
while (ioctl(fd, TIOCMIWAIT, pp->value) == 0) {
(void)fprintf(stderr, "%s Transition on %s\n", pp->name, device);
}
(void)fprintf(stderr,
"TIOCMIWAIT returns nonzero value on %s!\n",
device);
break;

case poll:
{
struct timeval tv_jw;
int state, lastState;
double lastTime = 0;
// for computing average length of a second, as derived from the
// rising edge of the pulse
double total = 0;
int samples = 0;

// poll selected line looking for transition; when found, report
// time and various intervals between successive transitions.
(void)fprintf(stderr,
"Testing TIOCMGET. Polling %s on %s\n",
pp->name, device);

// get the current state of the line
if (ioctl(fd, TIOCMGET, &lastState) != 0) {
(void)fprintf(stderr, "TIOCMGET fails on %s\n", device);
exit(1);
}
lastState = (int)((lastState & pp->value) != 0);

// loop forever
while (1) {
// get the value of the serial lines
if (ioctl(fd, TIOCMGET, &state) != 0) {
// abort on error
(void)fprintf(stderr, "TIOCMGET fails on %s\n", device);
exit(1);
}
// recover line state
state = (int)((state & pp->value) != 0);

// Transition?
if (state != lastState) {
// yes. Update the last state
lastState = state;
// Is this a leading (rising) edge?
if (state == 1) {
// yes. let's call this the top of the second
// note the system time
(void)gettimeofday(&tv_jw,NULL);
// turn it into a double
double curTime = tv_jw.tv_sec + tv_jw.tv_usec/1.0e6;
// how long since the last transition?
double diff = curTime - lastTime;
// Update time of 'last' state transition
lastTime = curTime;
// diff should be (really close to) one second
// is diff within reason? (Sometimes transitions appear to be missed)
if (diff < 1.5) {
// update for averaging
total += diff;
samples++;
// report on the times associated with this transition
(void)fprintf(stderr,
"%s transition on %s: %d: %.6f, %6f, %6f\n",
pp->name, device, state, curTime, diff, total/samples);
}
else {
(void)fprintf(stderr,
"%s transition on %s: %d: %.6f, %6f - wacky diff\n",
pp->name, device, state, curTime, diff);
}
}
}
// now sleep for a (very) little while
tv_jw.tv_sec = 0;
tv_jw.tv_usec = 1;
int retval_jw = select(1, NULL, NULL, NULL, &tv_jw);
}
}
break;

default:
(void)fprintf(stderr, "Unknown mode\n");
}

(void)close(fd);
return 0;
}

+ 48
- 42
driver_aivdm.c View File

@@ -485,7 +485,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
case 13: /* Safety Related Acknowledge */
{
unsigned int mmsi[4];
if (ais_context->bitlen < 72 || ais_context->bitlen > 168) {
if (ais_context->bitlen < 72 || ais_context->bitlen > 158) {
gpsd_report(LOG_WARN, "AIVDM message type %d size is out of range (%zd).\n",
ais->type,
ais_context->bitlen);
@@ -979,15 +979,19 @@ bool aivdm_decode(const char *buf, size_t buflen,
ais_context->bitlen);
return false;
}
if (ais_context->mmsi24) {
gpsd_report(LOG_WARN,
"AIVDM message type 24 collision on channel %c : Discarding previous sentence 24A from %09u.\n",
field[4][0],
ais_context->mmsi24);
/* no return false */
/* save incoming 24A shipname/MMSI pairs in a circular queue */
{
struct aivdm_type24a_t *saveptr = ais_context->type24names + ais_context->type24_index;

gpsd_report(LOG_PROG,
"AIVDM channel %c: 24A from %09u stashed.\n",
field[4][0],
ais->mmsi);
saveptr->mmsi = ais->mmsi;
UCHARS(40, saveptr->shipname);
++ais_context->type24_index;
ais_context->type24_index %= MAX_TYPE24_INTERLEAVE;
}
ais_context->mmsi24 = ais->mmsi;
UCHARS(40, ais_context->shipname24);
//ais->type24.a.spare = UBITS(160, 8);
return false; /* data only partially decoded */
case 1:
@@ -996,41 +1000,43 @@ bool aivdm_decode(const char *buf, size_t buflen,
ais_context->bitlen);
return false;
}
if (ais_context->mmsi24 != ais->mmsi) {
if (ais_context->mmsi24)
gpsd_report(LOG_WARN,
"AIVDM message type 24 collision on channel %c: MMSI mismatch: %09u vs %09u.\n",
field[4][0],
ais_context->mmsi24, ais->mmsi);
else
gpsd_report(LOG_WARN,
"AIVDM message type 24 collision on channel %c: 24B sentence from %09u without 24A.\n",
field[4][0],
ais->mmsi);
return false;
}
(void)strlcpy(ais->type24.shipname,
ais_context->shipname24,
sizeof(ais_context->shipname24));
ais->type24.shiptype = UBITS(40, 8);
UCHARS(48, ais->type24.vendorid);
UCHARS(90, ais->type24.callsign);
if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
ais->type24.mothership_mmsi = UBITS(132, 30);
} else {
ais->type24.dim.to_bow = UBITS(132, 9);
ais->type24.dim.to_stern = UBITS(141, 9);
ais->type24.dim.to_port = UBITS(150, 6);
ais->type24.dim.to_starboard = UBITS(156, 6);
/* search the 24A queue for a matching MMSI */
for (i = 0; i < MAX_TYPE24_INTERLEAVE; i++) {
if (ais_context->type24names[i].mmsi == ais->mmsi) {
(void)strlcpy(ais->type24.shipname,
ais_context->type24names[i].shipname,
sizeof(ais_context->type24names[i].shipname));
ais->type24.shiptype = UBITS(40, 8);
UCHARS(48, ais->type24.vendorid);
UCHARS(90, ais->type24.callsign);
if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
ais->type24.mothership_mmsi = UBITS(132, 30);
} else {
ais->type24.dim.to_bow = UBITS(132, 9);
ais->type24.dim.to_stern = UBITS(141, 9);
ais->type24.dim.to_port = UBITS(150, 6);
ais->type24.dim.to_starboard = UBITS(156, 6);
}
//ais->type24.b.spare = UBITS(162, 8);
gpsd_report(LOG_PROG,
"AIVDM 24B channel %c: 24B from %09u matches a 24A.\n",
field[4][0],
ais->mmsi);
/* prevent false match if a 24B is repeated */
ais_context->type24names[i].mmsi = 0;
return true;
}
}
//ais->type24.b.spare = UBITS(162, 8);
ais_context->mmsi24 = 0; /* reset last know 24A for collision detection */
break;
gpsd_report(LOG_WARN,
"AIVDM 24B channel %c: 24B from %09u can't be matched to a 24A.\n",
field[4][0],
ais->mmsi);
return false;
default:
gpsd_report(LOG_WARN, "AIVDM message type 24 of subtype unknown.\n");
return false;
}
break;
// break;
case 25: /* Binary Message, Single Slot */
/* this check and the following one reject line noise */
if (ais_context->bitlen < 40 || ais_context->bitlen > 168) {
@@ -1051,10 +1057,10 @@ bool aivdm_decode(const char *buf, size_t buflen,
/*
* Not possible to do this right without machinery we
* don't yet have. The problem is that if the addressed
* bit is on the bitfield start won't be on a byte
* bit is on, the bitfield start won't be on a byte
* boundary. Thus the formulas below (and in message type 26)
* will work perfectly for brodacst messages, but for addressed
* messages the retrieved data will be led by thr 30 bits of
* will work perfectly for broadcast messages, but for addressed
* messages the retrieved data will be led by the 30 bits of
* the destination MMSI
*/
ais->type25.bitcount = ais_context->bitlen - 40 - 16*ais->type25.structured;


+ 104
- 35
driver_nmea.c View File

@@ -367,10 +367,9 @@ static gps_mask_t processGPGGA(int c UNUSED, char *field[],
* If we see this, force mode to 2D at most.
*/
if (altitude[0] == '\0') {
if (session->newdata.mode == MODE_3D) {
session->newdata.mode =
session->gpsdata.status ? MODE_2D : MODE_NO_FIX;
mask |= MODE_SET;
if (session->newdata.mode > MODE_2D) {
session->newdata.mode = MODE_2D;
mask |= MODE_SET;
}
} else {
session->newdata.altitude = safe_atof(altitude);
@@ -723,7 +722,7 @@ static gps_mask_t processGPZDA(int c UNUSED, char *field[],

if (field[1][0] == '\0' || field[2][0] == '\0' || field[3][0] == '\0'
|| field[4][0] == '\0') {
gpsd_report(LOG_WARN, "malformed ZDA\n");
gpsd_report(LOG_WARN, "ZDA fields are empty\n");
} else {
int year, mon, mday, century;

@@ -813,6 +812,53 @@ static gps_mask_t processHDT(int c UNUSED, char *field[],
return mask;
}

static gps_mask_t processDBT(int c UNUSED, char *field[],
struct gps_device_t *session)
{
/*
* $SDDBT,7.7,f,2.3,M,1.3,F*05
* 1) Depth below sounder in feet
* 2) Fixed value 'f' indicating feet
* 3) Depth below sounder in meters
* 4) Fixed value 'M' indicating meters
* 5) Depth below sounder in fathoms
* 6) Fixed value 'F' indicating fathoms
* 7) Checksum.
*
* In real-world sensors, sometimes not all three conversions are reported.
*/
gps_mask_t mask;
mask = ONLINE_SET;

if (field[3][0] != '\0') {
session->newdata.altitude = -safe_atof(field[3]);
mask |= (ALTITUDE_SET);
} else if (field[1][0] != '\0') {
session->newdata.altitude = -safe_atof(field[1]) / METERS_TO_FEET;
mask |= (ALTITUDE_SET);
} else if (field[5][0] != '\0') {
session->newdata.altitude = -safe_atof(field[5]) / METERS_TO_FATHOMS;
mask |= (ALTITUDE_SET);
}

if ((mask & ALTITUDE_SET) != 0) {
if (session->newdata.mode < MODE_3D) {
session->newdata.mode = MODE_3D;
mask |= MODE_SET;
}
}

/*
* Hack: We report depth below keep as negative altitude because there's
* no better place to put it. Should work in practice as nobody is
* likely to be operating a depth sounder at varying altitudes.
*/
gpsd_report(LOG_RAW, "mode %d, depth %lf.\n",
session->newdata.mode,
session->newdata.altitude);
return mask;
}

#ifdef TNT_ENABLE
static gps_mask_t processTNTHTM(int c UNUSED, char *field[],
struct gps_device_t *session)
@@ -927,7 +973,7 @@ static gps_mask_t processOHPR(int c UNUSED, char *field[],
session->gpsdata.attitude.acc_z = safe_atof(field[13]);
session->gpsdata.attitude.gyro_x = safe_atof(field[15]);
session->gpsdata.attitude.gyro_y = safe_atof(field[16]);
mask |= (ALTITUDE_SET);
mask |= (ATTITUDE_SET);

gpsd_report(LOG_RAW, "Heading %lf.\n", session->gpsdata.attitude.heading);
return mask;
@@ -1024,13 +1070,14 @@ gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
{
char *name;
int nf; /* minimum number of fields required to parse */
bool cycle_continue; /* cycle continuer? */
nmea_decoder decoder;
} nmea_phrase[] = {
/*@ -nullassign @*/
{"PGRMC", 0, NULL}, /* ignore Garmin Sensor Config */
{"PGRME", 7, processPGRME},
{"PGRMI", 0, NULL}, /* ignore Garmin Sensor Init */
{"PGRMO", 0, NULL}, /* ignore Garmin Sentence Enable */
{"PGRMC", 0, false, NULL}, /* ignore Garmin Sensor Config */
{"PGRME", 7, false, processPGRME},
{"PGRMI", 0, false, NULL}, /* ignore Garmin Sensor Init */
{"PGRMO", 0, false, NULL}, /* ignore Garmin Sentence Enable */
/*
* Basic sentences must come after the PG* ones, otherwise
* Garmins can get stuck in a loop that looks like this:
@@ -1040,29 +1087,32 @@ gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
* 2. PGRMC is sent to reconfigure to Garmin binary mode.
* If successful, the GPS echoes the phrase.
*
* 3. nmea_parse() sees the echo as RMC because the talker ID is
* ignored, and fails to recognize the echo as PGRMC and ignore it.
* 3. nmea_parse() sees the echo as RMC because the talker
* ID is ignored, and fails to recognize the echo as
* PGRMC and ignore it.
*
* 4. The mode is changed back to NMEA, resulting in an infinite loop.
* 4. The mode is changed back to NMEA, resulting in an
* infinite loop.
*/
{"RMC", 8, processGPRMC},
{"GGA", 13, processGPGGA},
{"GST", 8, processGPGST},
{"GLL", 7, processGPGLL},
{"GSA", 17, processGPGSA},
{"GSV", 0, processGPGSV},
{"VTG", 0, NULL}, /* ignore Velocity Track made Good */
{"ZDA", 4, processGPZDA},
{"GBS", 7, processGPGBS},
{"HDT", 1, processHDT},
{"RMC", 8, false, processGPRMC},
{"GGA", 13, false, processGPGGA},
{"GST", 8, false, processGPGST},
{"GLL", 7, false, processGPGLL},
{"GSA", 17, false, processGPGSA},
{"GSV", 0, false, processGPGSV},
{"VTG", 0, false, NULL}, /* ignore Velocity Track made Good */
{"ZDA", 4, false, processGPZDA},
{"GBS", 7, false, processGPGBS},
{"HDT", 1, false, processHDT},
{"DBT", 7, true, processDBT},
#ifdef TNT_ENABLE
{"PTNTHTM", 9, processTNTHTM},
{"PTNTHTM", 9, false, processTNTHTM},
#endif /* TNT_ENABLE */
#ifdef ASHTECH_ENABLE
{"PASHR", 3, processPASHR}, /* general handler for Ashtech */
{"PASHR", 3, false, processPASHR}, /* general handler for Ashtech */
#endif /* ASHTECH_ENABLE */
#ifdef OCEANSERVER_ENABLE
{"OHPR", 18, processOHPR},
{"OHPR", 18, false, processOHPR},
#endif /* OCEANSERVER_ENABLE */
/*@ +nullassign @*/
};
@@ -1141,6 +1191,8 @@ gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
(void)strlcpy(session->gpsdata.tag,
nmea_phrase[i].name,
MAXTAGLEN);
if (nmea_phrase[i].cycle_continue)
session->driver.nmea.cycle_continue = true;
/*
* Must force this to be nz, as we're going to rely on a zero
* value to mean "no previous tag" later.
@@ -1182,7 +1234,7 @@ gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
/*
* The end-of-cycle detector. This code depends on just one
* assumption: if a sentence with a timestamp occurs just before
* start of cycle, then it is always good to trigger a reort on
* start of cycle, then it is always good to trigger a report on
* that sentence in the future. For devices with a fixed cycle
* this should work perfectly, locking in detection after one
* cycle. Most split-cycle devices (Garmin 48, for example) will
@@ -1192,7 +1244,7 @@ gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
*/
if (session->driver.nmea.latch_frac_time) {
gpsd_report(LOG_PROG,
"%s reporting cycle started on %.2f.\n",
"%s sentence timestamped %.2f.\n",
session->driver.nmea.field[0],
session->driver.nmea.this_frac_time);
if (!GPS_TIME_EQUAL
@@ -1206,25 +1258,42 @@ gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
/*
* Have we seen a previously timestamped NMEA tag?
* If so, designate as end-of-cycle marker.
* But not if there are continuation sentences;
* those get sorted after the last timestamped sentence
*/
if (lasttag > 0
&& (session->driver.nmea.cycle_enders & (1 << lasttag)) ==
0) {
&& (session->driver.nmea.cycle_enders & (1 << lasttag)) == 0
&& !session->driver.nmea.cycle_continue) {
session->driver.nmea.cycle_enders |= (1 << lasttag);
gpsd_report(LOG_PROG,
"tagged %s as a cycle ender.\n",
nmea_phrase[lasttag - 1].name);
}
}
/* here's where we check for end-of-cycle */
if (session->driver.nmea.cycle_enders & (1 << thistag)) {
} else {
/* extend the cycle to an un-timestamped sentence? */
if ((session->driver.nmea.lasttag & session->driver.nmea.cycle_enders) != 0)
gpsd_report(LOG_PROG,
"%s is just after a cycle ender.\n",
session->driver.nmea.field[0]);
if (session->driver.nmea.cycle_continue) {
gpsd_report(LOG_PROG,
"%s ends a reporting cycle.\n",
"%s extends the reporting cycle.\n",
session->driver.nmea.field[0]);
retval |= REPORT_IS;
session->driver.nmea.cycle_enders &=~ (1 << session->driver.nmea.lasttag);
session->driver.nmea.cycle_enders |= (1 << thistag);
}
session->driver.nmea.lasttag = thistag;
}
/* here's where we check for end-of-cycle */
if ((session->driver.nmea.latch_frac_time || session->driver.nmea.cycle_continue)
&& (session->driver.nmea.cycle_enders & (1 << thistag))!=0) {
gpsd_report(LOG_PROG,
"%s ends a reporting cycle.\n",
session->driver.nmea.field[0]);
retval |= REPORT_IS;
}
if (session->driver.nmea.latch_frac_time)
session->driver.nmea.lasttag = thistag;

/* we might have a reliable end-of-cycle */
if (session->driver.nmea.cycle_enders != 0)


+ 3
- 2
gps.h View File

@@ -693,11 +693,11 @@ struct subframe_t {
uint8_t IODE;
/* Rate of Inclination Angle, 14 bits signed, scale2**-43,
* semi-circles/sec */
uint16_t IDOT;
int16_t IDOT;
double d_IDOT;
/* Cic, Amplitude of the Cosine Harmonic Correction Term to the
* Angle of Inclination, 16 bits signed, scale 2**-29, radians*/
uint16_t Cic;
int16_t Cic;
double d_Cic;
/* Cis, Amplitude of the Sine Harmonic Correction Term to the
* Angle of Inclination, 16 bits, unsigned, scale 2**-29, radians */
@@ -1753,6 +1753,7 @@ extern double wgs84_separation(double, double);
/* some multipliers for interpreting GPS output */
#define METERS_TO_FEET 3.2808399 /* Meters to U.S./British feet */
#define METERS_TO_MILES 0.00062137119 /* Meters to miles */
#define METERS_TO_FATHOMS 0.54680665 /* Meters to fathoms */
#define KNOTS_TO_MPH 1.1507794 /* Knots to miles per hour */
#define KNOTS_TO_KPH 1.852 /* Knots to kilometers per hour */
#define KNOTS_TO_MPS 0.51444444 /* Knots to meters per second */


+ 1
- 0
gps/misc.py View File

@@ -8,6 +8,7 @@ import time, calendar, math
# some multipliers for interpreting GPS output
METERS_TO_FEET = 3.2808399 # Meters to U.S./British feet
METERS_TO_MILES = 0.00062137119 # Meters to miles
METERS_TO_FATHOMS = 0.54680665 # Meters to fathoms
KNOTS_TO_MPH = 1.1507794 # Knots to miles per hour
KNOTS_TO_KPH = 1.852 # Knots to kilometers per hour
KNOTS_TO_MPS = 0.51444444 # Knots to meters per second


+ 39
- 2
gpscap.ini View File

@@ -459,7 +459,7 @@ vendor_site = http://www.transystem.com.tw/
[Techway]
type = vendor
vendor_site = http://www.techwayinc.com.tw/
notes = This vendor has drooped off the web
notes = This vendor has dropped off the web

[TomTom]
type = vendor
@@ -513,7 +513,7 @@ packaging = mouse
techdoc = http://adapt-mobile.bosqom.com/default.php?page_ID=3&amp;spage_ID=1
uses = Nemerix
interfaces = Bluetooth, USB
iochip = pl2303
usbchip = pl2303
tested = 2.32
submitter = Dennis van Zuijlekom <tmib@xs4all.nl>.

@@ -961,6 +961,27 @@ nmea = 3.0
rating = broken
notes = This device does not have real-time data output, and is incompatible with GPSD.

[GPSmap 76S]
type = device
vendor = Garmin
engine = unknown
packaging = handset
rating = other
techdoc = http://www8.garmin.com/manuals/GPSMAP76S_OwnersManual.pdf
tested = 2.94
nmea = 2.3
date = 2011-10-24
interfaces = USB
submitter = Brad Skillman <brad.skillman@cobham.com>
model = GPSmap 76S
notes = When the GPSmap 76S is placed into simulator mode, for some
unknown reason, both the xgps and cgps clients display "n/a" in
the time field. However, the lat., long., and altitude fields
are being displayed correctly. Using gpspipe -r is appears that
the $GPGLL message is sending out the UTC time in the HHMMSS
format (Note: There are no fractional seconds being generated)
logs = GPSmap-76S

#% Geostar Navigation

[GeoS-1M]
@@ -2221,6 +2242,22 @@ notes = This receiver operates as a generic NMEA device, the Sony
more recent instances of gpsd break the probe writes into pieces
interleaved with read, and may no longer trigger this problem)

[UD731]
type = device
vendor = UniTraq
packaging = dongle
techdoc = http://www.unitraq.com/product_main.php?id=17
engine = Skytraq Venus 524c
rating = excellent
interfaces = USB
usbchip = CP2101
tested = 3.4
nmea = 3.01
submitter = Reported by Eric S. Raymond <esr@thyrsus.com>
notes = Device has two variants; the basic receiver is 'R' and the
version with additional data-logger capability is N. Emits only NMEA.
Some Web sources incorrectly describe it as SiRF-3-based.

#%Variotek

[VT-BT-204]


+ 1
- 1
gpsctl.1 View File

@@ -96,7 +96,7 @@ Force the device type\&.
.RS 4
Send a specified control string to the GPS;
gpsctl
will provide packet headers and trailers and checksum as appropriate for binary packet types, and whatever checksum and trailer is required for text packet types\&. (You must include the leading $ for NMEA packets\&.) When sending to a UBX device, the first two bytes of the string supplied will become the message class and type, and the remainder the payload\&. When sending to a Navcom NCT or Trimble TSIP device, the first byte is interpreted as the command ID and the rest as payload\&. When sending to a Zodiac device, the first two bytes are used as a message ID of type little\-endian short, and the remainder as payload in byte pairs interpreted as little\-endian short\&. C\-style backslash escapes in the string, notably \exNN for hex, will be interpreted; additionally, \ee will be replaced with ESC\&. This switch implies
will provide packet headers and trailers and checksum as appropriate for binary packet types, and whatever checksum and trailer is required for text packet types\&. (You must include the leading $ for NMEA packets\&.) When sending to a UBX device, the first two bytes of the string supplied will become the message class and type, and the remainder the payload\&. When sending to a Navcom NCT or Trimble TSIP device, the first byte is interpreted as the command ID and the rest as payload\&. When sending to a Zodiac device, the first two bytes are used as a message ID of type little\-endian short, and the remainder as payload in byte pairs interpreted as little\-endian short\&. For all other supported binary GPSes (notably including SiRF) the string is taken as the entire message payload and wrapped with appropriate header, trailer and checksum bytes\&. C\-style backslash escapes in the string, notably \exNN for hex, will be interpreted; additionally, \ee will be replaced with ESC\&. This switch implies
\fB\-f\fR\&.
.RE
.PP


+ 40
- 7
gpsctl.c View File

@@ -83,28 +83,45 @@ static gps_mask_t get_packet(struct gps_device_t *session)
{
static fd_set rfds;
gps_mask_t fieldmask;
#ifdef COMPAT_SELECT
struct timeval tv;
#else
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);
#endif /* COMPAT_SELECT */

FD_ZERO(&rfds);
for (;;) {
FD_CLR(session->gpsdata.gps_fd, &rfds);

/*@ -usedef @*/
/*@ -usedef -type -nullpass -compdef @*/
/*
* If the timeout on this select isn't longer than the device's
* cycle time, the code will be prone to flaky timing-dependent
* failures.
*/
errno = 0;
tv.tv_sec = 2;
#ifdef COMPAT_SELECT
tv.tv_usec = 0;
errno = 0;
if (select(session->gpsdata.gps_fd + 1, &rfds, NULL, NULL, &tv) == -1) {
#else
tv.tv_nsec = 0;
if (pselect(session->gpsdata.gps_fd + 1, &rfds, NULL, NULL, &tv, &oldset) == -1) {
#endif
if (errno == EINTR || !FD_ISSET(session->gpsdata.gps_fd, &rfds))
continue;
gpsd_report(LOG_ERROR, "select %s\n", strerror(errno));
exit(2);
}
/*@ +usedef @*/
/*@ +usedef +type +nullpass +compdef @*/

fieldmask = gpsd_poll(session);

@@ -138,10 +155,22 @@ static bool gps_query(/*@out@*/struct gps_data_t *gpsdata,
/* ship a command and wait on an expected response type */
{
static fd_set rfds;
struct timeval tv;
char buf[BUFSIZ];
va_list ap;
time_t starttime;
#ifdef COMPAT_SELECT
struct timeval tv;
#else
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);
#endif /* COMPAT_SELECT */

va_start(ap, fmt);
(void)vsnprintf(buf, sizeof(buf)-2, fmt, ap);
@@ -163,17 +192,21 @@ static bool gps_query(/*@out@*/struct gps_data_t *gpsdata,

gpsd_report(LOG_PROG, "waiting...\n");

/*@ -usedef @*/
/*@ -usedef -type -nullpass -compdef @*/
tv.tv_sec = 2;
#ifdef COMPAT_SELECT
tv.tv_usec = 0;
errno = 0;
if (select(gpsdata->gps_fd + 1, &rfds, NULL, NULL, &tv) == -1) {
#else
tv.tv_nsec = 0;
if (pselect(gpsdata->gps_fd + 1, &rfds, NULL, NULL, &tv, &oldset) == -1) {
#endif
if (errno == EINTR || !FD_ISSET(gpsdata->gps_fd, &rfds))
continue;
gpsd_report(LOG_ERROR, "select %s\n", strerror(errno));
exit(2);
}
/*@ +usedef @*/
/*@ +usedef +type +nullpass +compdef @*/

gpsd_report(LOG_PROG, "reading...\n");



+ 6
- 4
gpsctl.xml View File

@@ -143,10 +143,12 @@ a Navcom NCT or Trimble TSIP device, the first byte is interpreted as
the command ID and the rest as payload. When sending to a Zodiac
device, the first two bytes are used as a message ID of type
little-endian short, and the remainder as payload in byte pairs
interpreted as little-endian short. C-style backslash escapes in the
string, notably \xNN for hex, will be interpreted; additionally, \e
will be replaced with ESC. This switch implies
<option>-f</option>.</para>
interpreted as little-endian short. For all other supported binary
GPSes (notably including SiRF) the string is taken as the entire
message payload and wrapped with appropriate header, trailer and
checksum bytes. C-style backslash escapes in the string, notably \xNN
for hex, will be interpreted; additionally, \e will be replaced with
ESC. This switch implies <option>-f</option>.</para>
</listitem>
</varlistentry>



+ 18
- 2
gpsd.8 View File

@@ -594,6 +594,22 @@ refclock SHM 1 offset 0\&.0 delay 0\&.0
.\}
.PP
To get chronyd to connect to gpsd using the more precise socket method add this to your /etc/chrony/chrony\&.conf file (replacing ttyXX with your device name):
.PP
If running as root:
.sp
.if n \{\
.RS 4
.\}
.nf
#refclock PPS
refclock SOCK /var/run/chrony\&.ttyXX\&.sock
.fi
.if n \{\
.RE
.\}
.PP
If not running as root:
.sp
.if n \{\
.RS 4
@@ -601,7 +617,7 @@ To get chronyd to connect to gpsd using the more precise socket method add this
.nf
#refclock PPS
/dev/pps0 refclock SOCK /tmp/chrony\&.ttyXX\&.sock
refclock SOCK /tmp/chrony\&.ttyXX\&.sock
.fi
.if n \{\
.RE
@@ -680,7 +696,7 @@ gpsd
have made a point of not looking at it\&. The GPSD project website links to several documents that collect publicly disclosed information about the protocol\&.
.PP
gpsd
parses the following NMEA sentences: RMC, GGA, GLL, GSA, GSV, VTG, ZDA\&. It recognizes these with either the normal GP talker\-ID prefix, or with the GN prefix used by GLONASS, or with the II prefix emitted by Seahawk Autohelm marine navigation systems, or with the IN prefix emitted by some Garmin units, or with the EC prefix emitted by ECDIS units\&. It recognizes some vendor extensions: the PGRME emitted by some Garmin GPS models, the OHPR emitted by Oceanserver digital compasses, the PTNTHTM emitted by True North digital compasses, and the PASHR sentences emitted by some Ashtech GPSes\&.
parses the following NMEA sentences: RMC, GGA, GLL, GSA, GSV, VTG, ZDA, GBS, HDT, DBT\&. It recognizes these with either the normal GP talker\-ID prefix, or with the GN prefix used by GLONASS, or with the II prefix emitted by Seahawk Autohelm marine navigation systems, or with the IN prefix emitted by some Garmin units, or with the EC prefix emitted by ECDIS units, or with the SD prefix emitted by depth sounders\&. It recognizes some vendor extensions: the PGRME emitted by some Garmin GPS models, the OHPR emitted by Oceanserver digital compasses, the PTNTHTM emitted by True North digital compasses, and the PASHR sentences emitted by some Ashtech GPSes\&.
.PP
Note that
gpsd


+ 123
- 41
gpsd.c View File

@@ -9,6 +9,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h> /* for select() */
#include <sys/select.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
@@ -24,6 +25,7 @@
#include <syslog.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#ifndef S_SPLINT_S
#include <netdb.h>
@@ -42,6 +44,11 @@

#include "gpsd_config.h"

#if defined(HAVE_LIBCAP) && !defined(S_SPLINT_S)
#include <sys/capability.h>
#include <sys/prctl.h>
#endif /* HAVE_LIBCAP */

#include "gpsd.h"
#include "sockaddr.h"
#include "gps_json.h"
@@ -583,7 +590,17 @@ static ssize_t throttled_write(struct subscriber_t *sub, char *buf,
}
}

#if defined(PPS_ENABLE)
/*@ -unrecog (splint has no pthread declarations as yet) @*/
(void)pthread_mutex_lock(&report_mutex);
/* +unrecog */
#endif /* PPS_ENABLE */
status = send(sub->fd, buf, len, 0);
#if defined(PPS_ENABLE)
/*@ -unrecog (splint has no pthread declarations as yet) @*/
(void)pthread_mutex_unlock(&report_mutex);
/* +unrecog */
#endif /* PPS_ENABLE */
if (status == (ssize_t) len)
return status;
else if (status > -1) {
@@ -633,6 +650,8 @@ static void deactivate_device(struct gps_device_t *device)
if (device->gpsdata.gps_fd != -1) {
FD_CLR(device->gpsdata.gps_fd, &all_fds);
adjust_max_fd(device->gpsdata.gps_fd, false);
#if defined(PPS_ENABLE) && defined(TIOCMIWAIT)
#endif /* defined(PPS_ENABLE) && defined(TIOCMIWAIT) */
#ifdef NTPSHM_ENABLE
ntpd_link_deactivate(device);
#endif /* NTPSHM_ENABLE */
@@ -1481,8 +1500,9 @@ static void consume_packets(struct gps_device_t *device)
&& sub->policy.watcher
&& subscribed(sub, device))
listeners = true;
if (listeners)
if (listeners) {
(void)awaken(device);
}
}

/* handle laggy response to a firmware version query */
@@ -1497,8 +1517,7 @@ static void consume_packets(struct gps_device_t *device)
#endif /* SOCKET_EXPORT_ENABLE */

/*
* If the device provided an RTCM packet, stash it
* in the context structure for use as a future correction.
* If the device provided an RTCM packet, repeat it to all devices.
*/
if ((changed & RTCM2_SET) != 0 || (changed & RTCM3_SET) != 0) {
if (device->packet.outbuflen > RTCM_MAX) {
@@ -1506,11 +1525,23 @@ static void consume_packets(struct gps_device_t *device)
"overlong RTCM packet (%zd bytes)\n",
device->packet.outbuflen);
} else {
context.rtcmbytes = device->packet.outbuflen;
memcpy(context.rtcmbuf,
device->packet.outbuffer,
context.rtcmbytes);
context.rtcmtime = timestamp();
struct gps_device_t *dp;
for (dp = devices; dp < devices+MAXDEVICES; dp++) {
if (allocated_device(dp)) {
/* *INDENT-OFF* */
if (dp->device_type->rtcm_writer != NULL) {
if (dp->device_type->rtcm_writer(dp,
(const char *)device->packet.outbuffer,
device->packet.outbuflen) == 0)
gpsd_report(LOG_ERROR, "Write to RTCM sink failed\n");
else {
gpsd_report(LOG_IO, "<= DGPS: %zd bytes of RTCM relayed.\n",
device->packet.outbuflen);
}
}
/* *INDENT-ON* */
}
}
}
}

@@ -1664,6 +1695,22 @@ static int handle_gpsd_request(struct subscriber_t *sub, const char *buf)
}
#endif /* SOCKET_EXPORT_ENABLE */

#ifdef PPS_ENABLE
static void ship_pps_drift_message(struct gps_device_t *session,
struct timeval *tv)
/* on PPS interrupt, ship a drift message to all clients */
{
struct timeval clocktime;

if (gettimeofday(&clocktime, NULL) == 0)
notify_watchers(session, "{\"class\":\"PPS\",\"device\":\"%s\",\"real_sec\":%ld, \"real_musec\":%ld,\"clock_sec\":%ld,\"clock_musec\":%ld}\r\n",
session->gpsdata.dev.path,
tv->tv_sec, tv->tv_usec,
clocktime.tv_sec, clocktime.tv_usec);
}
#endif /* PPS_ENABLE */


#ifdef __UNUSED_AUTOCONNECT__
#define DGPS_THRESHOLD 1600000 /* max. useful dist. from DGPS server (m) */
#define SERVER_SAMPLE 12 /* # of servers within threshold to check */
@@ -1765,18 +1812,24 @@ int main(int argc, char *argv[])
int i, option, dfd;
int msocks[2] = {-1, -1};
bool go_background = true;
#ifdef COMPAT_SELECT
struct timeval tv;
#else
sigset_t oldset, blockset;
#endif /* COMPAT_SELECT */
const struct gps_type_t **dp;
bool in_restart;

context.debug = 0;
gps_context_init(&context);

#ifdef PPS_ENABLE
/*@-nullpass@*/
(void)pthread_mutex_init(&report_mutex, NULL);
/*@+nullpass@*/
context.pps_hook = ship_pps_drift_message;
#endif /* PPS_ENABLE */

context.debug = 0;
gps_context_init(&context);
while ((option = getopt(argc, argv, "F:D:S:bGhlNnP:V")) != -1) {
switch (option) {
case 'D':
@@ -1997,6 +2050,12 @@ int main(int argc, char *argv[])
struct passwd *pw;
struct stat stb;

#if defined(HAVE_LIBCAP) && !defined(S_SPLINT_S)
/* set flag: keep privileges across setuid() call */
if (prctl(PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L) == -1)
gpsd_report(LOG_ERR, "prctl(PR_SET_KEEPCAPS, 1L ) failed\n");
#endif /* HAVE_LIBCAP */

/* make default devices accessible even after we drop privileges */
for (i = optind; i < argc; i++)
if (stat(argv[i], &stb) == 0)
@@ -2029,6 +2088,20 @@ int main(int argc, char *argv[])
if (pw)
(void)setuid(pw->pw_uid);
/*@+type@*/

#if defined(HAVE_LIBCAP) && !defined(S_SPLINT_S)
/* drop root capabilities, except CAP_SYS_TIME for 1PPS support */
{
cap_t caps = cap_from_text("cap_sys_time=pe");

if (!caps)
gpsd_report(LOG_ERR, "cap_from_text() failed.\n");
else if (cap_set_proc(caps) == -1) {
gpsd_report(LOG_ERR, "cap_set_proc() failed to drop root privs\n");
cap_free(caps);
}
}
#endif /* HAVE_LIBCAP */
}
gpsd_report(LOG_INF, "running with effective group ID %d\n", getegid());
gpsd_report(LOG_INF, "running with effective user ID %d\n", geteuid());
@@ -2038,6 +2111,31 @@ int main(int argc, char *argv[])
subscribers[i].fd = UNALLOCATED_FD;
#endif /* SOCKET_EXPORT_ENABLE*/

/* Handle some signals */
#ifndef COMPAT_SELECT
(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);
#endif /* COMPAT_SELECT */

/*@-compdef -compdestroy@*/
{
struct sigaction sa;

sa.sa_flags = 0;
sa.sa_handler = onsig;
(void)sigfillset(&sa.sa_mask);
(void)sigaction(SIGHUP, &sa, NULL);
(void)sigaction(SIGINT, &sa, NULL);
(void)sigaction(SIGTERM, &sa, NULL);
(void)sigaction(SIGQUIT, &sa, NULL);
(void)signal(SIGPIPE, SIG_IGN);
}
/*@+compdef +compdestroy@*/

/* daemon got termination or interrupt signal */
if (setjmp(restartbuf) > 0) {
/* try to undo all device configurations */
@@ -2049,13 +2147,7 @@ int main(int argc, char *argv[])
gpsd_report(LOG_WARN, "gpsd restarted by SIGHUP\n");
}

/* Handle some signals */
signalled = 0;
(void)signal(SIGHUP, onsig);
(void)signal(SIGINT, onsig);
(void)signal(SIGTERM, onsig);
(void)signal(SIGQUIT, onsig);
(void)signal(SIGPIPE, SIG_IGN);

for (i = 0; i < AFCOUNT; i++)
if (msocks[i] >= 0) {
@@ -2094,18 +2186,27 @@ int main(int argc, char *argv[])
* of tracking maxfd is to keep the set of descriptors that
* select(2) has to poll here as small as possible (for
* low-clock-rate SBCs and the like).
*
* pselect() is preferable, when we can have it, to eliminate
* the once-per-second wakeup when no sensors are attached.
* This cuts power consumption.
*/
/*@ -usedef @*/
/*@ -usedef -nullpass @*/
errno = 0;

#ifdef COMPAT_SELECT
tv.tv_sec = 1;
tv.tv_usec = 0;
errno = 0;
if (select(maxfd + 1, &rfds, NULL, NULL, &tv) == -1) {
#else
if (pselect(maxfd + 1, &rfds, NULL, NULL, NULL, &oldset) == -1) {
#endif
if (errno == EINTR)
continue;
gpsd_report(LOG_ERROR, "select: %s\n", strerror(errno));
exit(2);
}
/*@ +usedef @*/
/*@ +usedef +nullpass @*/

if (context.debug >= LOG_SPIN) {
char dbuf[BUFSIZ];
@@ -2203,8 +2304,10 @@ int main(int argc, char *argv[])
for (cfd = 0; cfd < FD_SETSIZE; cfd++)
if (FD_ISSET(cfd, &control_fds)) {
char buf[BUFSIZ];
ssize_t rd;

while (read(cfd, buf, sizeof(buf) - 1) > 0) {
while ((rd = read(cfd, buf, sizeof(buf) - 1)) > 0) {
buf[rd] = '\0';
gpsd_report(LOG_IO, "<= control(%d): %s\n", cfd, buf);
handle_control(cfd, buf);
}
@@ -2221,27 +2324,6 @@ int main(int argc, char *argv[])
if (!allocated_device(device))
continue;

/* *INDENT-OFF* */
/* pass the current RTCM correction to the GPS if new */
if (device->device_type != NULL) {
if (device->gpsdata.gps_fd != -1
&& device->context->rtcmbytes > 0
&& device->rtcmtime < device->context->rtcmtime
&& device->device_type->rtcm_writer != NULL) {
if (device->device_type->rtcm_writer(device,
device->context->rtcmbuf,
device->context->rtcmbytes) ==
0)
gpsd_report(LOG_ERROR, "Write to RTCM sink failed\n");
else {
device->rtcmtime = timestamp();
gpsd_report(LOG_IO, "<= DGPS: %zd bytes of RTCM relayed.\n",
device->context->rtcmbytes);
}
}
}
/* *INDENT-ON* */

if (device->gpsdata.gps_fd >= 0) {
if (FD_ISSET(device->gpsdata.gps_fd, &rfds))
/* get data from the device */


+ 37
- 10
gpsd.h-tail View File

@@ -9,6 +9,10 @@
#include <stdint.h>
#include "gps.h"

#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>
#endif

#ifdef _WIN32
typedef unsigned int speed_t;
#endif
@@ -20,11 +24,13 @@ typedef unsigned int speed_t;
* 3.3: AIS app_id split into DAC and FID
* 3.4: Timestamps change from seconds since Unix epoch to ISO8601.
* 3.5: POLL subobject name changes: fixes -> tpv, skyview -> sky.
* DEVICE::activated becomes ISO8601 rather thab real.
* DEVICE::activated becomes ISO8601 rather than real.
* 3.6 VERSION, WATCH, and DEVICES from slave gpsds get "remote" attribute.
* 3.7 PPS message added to repertoire. SDDBT water depth reported as
* negative altitude with Mode 3 set.
*/
#define GPSD_PROTO_MAJOR_VERSION 3 /* bump on incompatible changes */
#define GPSD_PROTO_MINOR_VERSION 6 /* bump on compatible changes */
#define GPSD_PROTO_MINOR_VERSION 7 /* bump on compatible changes */

#define JSON_DATE_MAX 24 /* ISO8601 timestamp with 2 decimal places */

@@ -198,6 +204,8 @@ extern void rtcm3_unpack(/*@out@*/struct rtcm3_t *, char *);

#define AIVDM_CHANNELS 2 /* A, B */

struct gps_device_t;

struct gps_context_t {
int valid; /* member validity flags */
int debug; /* dehug verbosity level */
@@ -206,9 +214,6 @@ struct gps_context_t {
#define GPS_TIME_VALID 0x02 /* GPS week/tow is valid */
/* DGPS status */
int fixcnt; /* count of good fixes seen */
size_t rtcmbytes; /* byte count of last RTCM104 report */
char rtcmbuf[RTCM_MAX]; /* last RTCM104 report */
timestamp_t rtcmtime; /* timestamp of last RTCM104 report */
/* timekeeping */
time_t start_time; /* local time of daemon startup */
int leap_seconds; /* Unix seconds to UTC (GPS-UTC offset) */
@@ -224,6 +229,7 @@ struct gps_context_t {
bool shmTimeInuse[NTPSHMSEGS];
# ifdef PPS_ENABLE
bool shmTimePPS;
void (*pps_hook)(struct gps_device_t *, struct timeval *);
# endif /* PPS_ENABLE */
#endif /* NTPSHM_ENABLE */
#ifdef SHM_EXPORT_ENABLE
@@ -233,17 +239,22 @@ struct gps_context_t {
#endif
};


struct aivdm_type24a_t {
unsigned int mmsi;
char shipname[AIS_SHIPNAME_MAXLEN+1];
};
#define MAX_TYPE24_INTERLEAVE 8 /* max number of queued type 24s */

struct aivdm_context_t {
/* hold context for decoding AIDVM packet sequences */
int decoded_frags; /* for tracking AIDVM parts in a multipart sequence */
unsigned char bits[2048];
size_t bitlen; /* how many valid bits */
unsigned int mmsi24; /* type 24 specific */
char shipname24[AIS_SHIPNAME_MAXLEN+1]; /* type 24 specific */
struct aivdm_type24a_t type24names[MAX_TYPE24_INTERLEAVE];
int type24_index;
};

struct gps_device_t;

#define MODE_NMEA 0
#define MODE_BINARY 1

@@ -383,7 +394,6 @@ struct gps_device_t {
struct gps_context_t *context;
sourcetype_t sourcetype;
servicetype_t servicetype;
timestamp_t rtcmtime; /* timestamp of last RTCM104 correction to GPS */
#ifndef _WIN32
struct termios ttyset, ttyset_old;
#endif
@@ -409,6 +419,9 @@ struct gps_device_t {
bool ship_to_ntpd;
# ifdef PPS_ENABLE
int shmTimeP;
#if defined(HAVE_SYS_TIMEPPS_H)
pps_handle_t kernelpps_handle;
#endif /* defined(HAVE_SYS_TIMEPPS_H) */
# endif /* PPS_ENABLE */
#endif /* NTPSHM_ENABLE */
double mag_var; /* magnetic variation in degrees */
@@ -451,6 +464,7 @@ struct gps_device_t {
bool latch_frac_time;
unsigned int lasttag;
unsigned int cycle_enders;
bool cycle_continue;
#ifdef GPSCLOCK_ENABLE
bool ignore_trailing_edge;
#endif /* GPSCLOCK_ENABLE */
@@ -683,7 +697,13 @@ extern gps_mask_t gpsd_interpret_subframe(struct gps_device_t *, unsigned int,
extern gps_mask_t gpsd_interpret_subframe_raw(struct gps_device_t *,
unsigned int, uint32_t[]);
extern /*@ observer @*/ char *gpsd_hexdump(/*@null@*/char *, size_t);
# ifdef __cplusplus
extern "C" {
# endif
extern int gpsd_hexpack(/*@in@*/const char *, /*@out@*/char *, size_t);
# ifdef __cplusplus
}
# endif
extern ssize_t hex_escapes(/*@out@*/char *, const char *);
extern void gpsd_position_fix_dump(struct gps_device_t *,
/*@out@*/char[], size_t);
@@ -701,6 +721,8 @@ extern void ntpshm_init(struct gps_context_t *, bool);
extern int ntpshm_put(struct gps_device_t *, double, double);
extern void ntpd_link_deactivate(struct gps_device_t *);
extern void ntpd_link_activate(struct gps_device_t *);
extern void pps_thread_activate(struct gps_device_t *);
extern void pps_thread_deactivate(struct gps_device_t *);

extern void ecef_to_wgs84fix(/*@out@*/struct gps_fix_t *,
/*@out@*/double *,
@@ -792,6 +814,11 @@ extern struct tm *localtime_r(const time_t *,/*@out@*/struct tm *tp)/*@modifies

#define NITEMS(x) (int)(sizeof(x)/sizeof(x[0]))

/* Ugh - required for build on Solaris */
#ifndef NAN
#define NAN (0.0f/0.0f)
#endif

/* Cygwin, in addition to NAN, doesn't have cfmakeraw */
#if defined(__CYGWIN__)
void cfmakeraw(struct termios *);


+ 11
- 22
gpsd.php View File

@@ -88,8 +88,9 @@ if (isset($_GET['imgdata']) && $op == 'view'){
if ($testmode){
$sock = @fsockopen($server, $port, $errno, $errstr, 2);
@fwrite($sock, "?WATCH={\"enable\":true}\n");
usleep(100);
usleep(1000);
@fwrite($sock, "?POLL;\n");
usleep(1000);
for($tries = 0; $tries < 10; $tries++){
$resp = @fread($sock, 2000); # SKY can be pretty big
if (preg_match('/{"class":"POLL".+}/i', $resp, $m)){
@@ -590,40 +591,28 @@ function gen_osm_head() {
global $GPS;
return <<<EOT
<script src="http://openlayers.org/api/OpenLayers.js" type="text/javascript"></script>
<script src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js" type="text/javascript"></script>
<script type="text/javascript">
<!--
// Create a base icon for all of our markers that specifies the shadow, icon
// dimensions, etc.
function Load() {
document.getElementById("map").firstChild.data = "";
map = new OpenLayers.Map("map", {
var map = new OpenLayers.Map("map", {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.LayerSwitcher()
],
maxResolution: 156543.0339,
numZoomLevels: 20,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
]
});
var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");
map.addLayer(layerMapnik);
var layer = new OpenLayers.Layer.OSM("Open Street Map");
map.addLayer(layer);

var layerTilesAtHome = new OpenLayers.Layer.OSM.Osmarender("Osmarender");
map.addLayer(layerTilesAtHome);
var center = new OpenLayers.LonLat({$GLOBALS['lon']}, {$GLOBALS['lat']})
.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.setCenter(center, 12);

center = new OpenLayers.LonLat({$GLOBALS['lon']}, {$GLOBALS['lat']}).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());

markers = new OpenLayers.Layer.Markers( "Markers" );
centermarker = new OpenLayers.Marker(center);
markers.addMarker(centermarker);
var markers = new OpenLayers.Layer.Markers("Markers");
markers.addMarker(new OpenLayers.Marker(center));
map.addLayer(markers);

map.setCenter(center, 17);
}
-->
</script>


+ 11
- 22
gpsd.php.in View File

@@ -88,8 +88,9 @@ if (isset($_GET['imgdata']) && $op == 'view'){
if ($testmode){
$sock = @fsockopen($server, $port, $errno, $errstr, 2);
@fwrite($sock, "?WATCH={\"enable\":true}\n");
usleep(100);
usleep(1000);
@fwrite($sock, "?POLL;\n");
usleep(1000);
for($tries = 0; $tries < 10; $tries++){
$resp = @fread($sock, 2000); # SKY can be pretty big
if (preg_match('/{"class":"POLL".+}/i', $resp, $m)){
@@ -590,40 +591,28 @@ function gen_osm_head() {
global $GPS;
return <<<EOT
<script src="http://openlayers.org/api/OpenLayers.js" type="text/javascript"></script>
<script src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js" type="text/javascript"></script>
<script type="text/javascript">
<!--
// Create a base icon for all of our markers that specifies the shadow, icon
// dimensions, etc.
function Load() {
document.getElementById("map").firstChild.data = "";
map = new OpenLayers.Map("map", {
var map = new OpenLayers.Map("map", {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.LayerSwitcher()
],
maxResolution: 156543.0339,
numZoomLevels: 20,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
]
});
var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");
map.addLayer(layerMapnik);
var layer = new OpenLayers.Layer.OSM("Open Street Map");
map.addLayer(layer);

var layerTilesAtHome = new OpenLayers.Layer.OSM.Osmarender("Osmarender");
map.addLayer(layerTilesAtHome);
var center = new OpenLayers.LonLat({$GLOBALS['lon']}, {$GLOBALS['lat']})
.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.setCenter(center, 12);

center = new OpenLayers.LonLat({$GLOBALS['lon']}, {$GLOBALS['lat']}).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());

markers = new OpenLayers.Layer.Markers( "Markers" );
centermarker = new OpenLayers.Marker(center);
markers.addMarker(centermarker);
var markers = new OpenLayers.Layer.Markers("Markers");
markers.addMarker(new OpenLayers.Marker(center));
map.addLayer(markers);

map.setCenter(center, 17);
}
-->
</script>


+ 2
- 0
gpsd.rules View File

@@ -31,6 +31,8 @@ ATTRS{idVendor}=="067b", ATTRS{idProduct}=="aaa0", SYMLINK+="gps%n", RUN+="/lib/
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="gps%n", RUN+="/lib/udev/gpsd.hotplug"
# Cypress M8/CY7C64013 (Delorme uses these) [linux module: cypress_m8]
ATTRS{idVendor}=="1163", ATTRS{idProduct}=="0100", SYMLINK+="gps%n", RUN+="/lib/udev/gpsd.hotplug"
# Cypress M8/CY7C64013 (DeLorme LT-40)
ATTRS{idVendor}=="1163", ATTRS{idProduct}=="0200", SYMLINK+="gps%n", RUN+="/lib/udev/gpsd.hotplug"
# Garmin International GPSmap, various models (tested with Garmin GPS 18 USB) [linux module: garmin_gps]
ATTRS{idVendor}=="091e", ATTRS{idProduct}=="0003", SYMLINK+="gps%n", RUN+="/lib/udev/gpsd.hotplug"
# Cygnal Integrated Products, Inc. CP210x Composite Device (Used by Holux m241 and Wintec grays2 wbt-201) [linux module: cp210x]


+ 14
- 6
gpsd.xml View File

@@ -706,9 +706,15 @@ refclock SHM 1 offset 0.0 delay 0.0
<para>To get chronyd to connect to gpsd using the more precise socket
method add this to your /etc/chrony/chrony.conf file (replacing ttyXX
with your device name): </para>
<para>If running as root:</para>
<screen>
#refclock PPS
/dev/pps0 refclock SOCK /tmp/chrony.ttyXX.sock
refclock SOCK /var/run/chrony.ttyXX.sock
</screen>
<para>If not running as root:</para>
<screen>
#refclock PPS
refclock SOCK /tmp/chrony.ttyXX.sock
</screen>
</refsect1>
<refsect1 id='dbus'><title>USE WITH D-BUS</title>
@@ -859,11 +865,13 @@ several documents that collect publicly disclosed information about
the protocol.</para>

<para><application>gpsd</application> parses the following NMEA
sentences: RMC, GGA, GLL, GSA, GSV, VTG, ZDA. It recognizes these
with either the normal GP talker-ID prefix, or with the GN prefix used
by GLONASS, or with the II prefix emitted by Seahawk Autohelm marine
navigation systems, or with the IN prefix emitted by some Garmin
units, or with the EC prefix emitted by ECDIS units. It recognizes
sentences:
RMC, GGA, GLL, GSA, GSV, VTG, ZDA, GBS, HDT, DBT.
It recognizes these with either the normal GP talker-ID prefix, or
with the GN prefix used by GLONASS, or with the II prefix emitted by
Seahawk Autohelm marine navigation systems, or with the IN prefix
emitted by some Garmin units, or with the EC prefix emitted by ECDIS
units, or with the SD prefix emitted by depth sounders. It recognizes
some vendor extensions: the PGRME emitted by some Garmin GPS models,
the OHPR emitted by Oceanserver digital compasses, the PTNTHTM emitted
by True North digital compasses, and the PASHR sentences emitted by


+ 123
- 18
gpsd_json.5 View File

@@ -1406,9 +1406,7 @@ Here\*(Aqs an example:
.PP
?POLL;
.RS 4
The POLL command requests data from the last\-seen fixes on all active GPS devices\&. Devices must previously have been activated by ?WATCH to be pollable, or have been specified on the GPSD command line together with an
\fB\-n\fR
option\&.
The POLL command requests data from the last\-seen fixes on all active GPS devices\&. Devices must previously have been activated by ?WATCH to be pollable\&.
.sp
Polling can lead to possibly surprising results when it is used on a device such as an NMEA GPS for which a complete fix has to be accumulated from several sentences\&. If you poll while those sentences are being emitted, the response will contain the last complete fix data and may be as much as one cycle time (typically 1 second) stale\&.
.sp
@@ -1531,6 +1529,113 @@ collects and caches more data from more sensor types, those data are likely to f
.RE
.RE
.PP
PPS
.RS 4
This message is emitted each time the daeon sees a PPS (Pulse Per Second) strobe from a device\&.
.sp
A PPS object has the following elements:
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.B Table\ \&11.\ \&PPS object
.TS
allbox tab(:);
lB lB lB lB.
T{
Name
T}:T{
Always?
T}:T{
Type
T}:T{
Description
T}
.T&
l l l l
l l l l
l l l l
l l l l
l l l l
l l l l.
T{
class
T}:T{
Yes
T}:T{
string
T}:T{
Fixed: "PPS"
T}
T{
device
T}:T{
Yes
T}:T{
string
T}:T{
Name of originating device
T}
T{
real_sec
T}:T{
Yes
T}:T{
numeric
T}:T{
seconds from the realtime clock
T}
T{
real_musec
T}:T{
Yes