summaryrefslogtreecommitdiff
path: root/www/client-howto.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'www/client-howto.adoc')
-rw-r--r--www/client-howto.adoc642
1 files changed, 642 insertions, 0 deletions
diff --git a/www/client-howto.adoc b/www/client-howto.adoc
new file mode 100644
index 00000000..96890035
--- /dev/null
+++ b/www/client-howto.adoc
@@ -0,0 +1,642 @@
+= GPSD Client HOWTO =
+:description: This document is a guide to interfacing client applications with GPSD.
+:keywords: time, GPSD, NTP, time, precision, 1PPS, PPS, stratum, jitter
+Eric S. Raymond <esr@thyrsus.com>
+v1.19, Jul 2015
+
+== Introduction ==
+
+This document is a guide to interfacing client applications with GPSD.
+It surveys the available bindings and their use cases. It also explains
+some sharp edges in the client API which, unfortunately, are fundamental
+results of the way GPS sensor devices operate, and suggests tactics
+for avoiding being cut.
+
+== Sensor behavior matters ==
+
+GPSD handles two main kinds of sensors: GPS receivers and AIS
+receivers. It has rudimentary support for some other kinds of
+specialized geolocation-related sensors as well, notably compass and
+yaw/pitch/roll, but those sensors are usually combined with GPS/AIS
+receivers and behave like them.
+
+In an ideal world, GPS/AIS sensors would be oracles that you could
+poll at any time to get clean data. But despite the existence of some
+vendor-specific query and control strings on some devices, a GPS/AIS
+sensor is not a synchronous device you can query for specified data
+and count on getting a response back from in a fixed period of time.
+It gets radio data on its own schedule (usually once per second for a
+GPS), and emits the reports it feels like reporting asynchronously
+with variable lag during the following second. *If* it supports query
+strings, reports from these are intermixed with the regular
+reports, and usually scheduled at a lower priority (often with a lag
+of more than a second).
+
+A GPS/AIS receiver, or any sensor that behaves like one, is in effect
+a datagram emitter similar to a UDP data source; you get no guarantees
+about sequence or timing at finer resolution than "TPV roughly once
+per second" (or whatever the main type of report and report interval
+is).
+
+The only way to simulate synchronous querying of such a sensor is to
+have an agent between you and it that caches the data coming out of
+the device; you can then query the agent and expect a reasonably
+synchronous response from the cache (we support this for
+GPSes). However, note that this doesn't work for a freshly opened
+device - there's no cached data.
+
+Consider what this implies for GPses, in particular:
+
+* You can't actually poll them. They report to you over a serial
+ (RS232 or USB-serial) interface at a fixed interval, usually once
+ per second.
+
+* They don't always have a fix to report, because they can only
+ get one when they have satellite lock.
+
+* They may fail to have satellite lock when your skyview is poor.
+ If you are moving through uneven terrain or anywhere with trees
+ or buildings, your skyview can degrade in an instant.
+
+* They may also fail to have lock because they're initially powering
+ on (cold start), or waking from a power-conserving sleep mode (warm
+ start). While most modern GPSes with a good skyview can get
+ satellite lock in 30 seconds from a warm start, a GPS that has
+ been off for a while can take 15 minutes or more to acquire lock
+
+Time to fix after a power-on matters because in many use cases for
+GPSes they're running off a battery, and you can't afford to keep them
+powered when you don't actually need location data. This is why GPS
+sensors are sometimes designed to go to a low-power mode when you close
+the serial port they're attached to.
+
+AIS receivers have a simpler set of constraints. They report
+navigational and ID information from any AIS transmitter in line of
+sight; there are no skyview issues, and they're ready instantly when
+powered up. Furthermore, they're not normally battery constrained.
+However, you don't poll them either; they receive information
+packets over the air and ship them to you at unpredictable intervals
+over a serial port.
+
+The design of the GPSD reporting protocol surrenders to reality. Its data
+packets translate the GPS's stream of datagrams into
+device-type-independent datagrams, but it can't impose timing and
+sequencing regularities on them that the underlying device doesn't
+already obey.
+
+== What GPSD does, and what it cannot do ==
+
+GPSD solves some of the problems with GPS/AIS sensors. First:
+multiplexing; it allows multiple applications to get sensor data
+without having to contend for a single serial device. Second:
+coping with the hideous gallimaufry of badly-designed protocols these
+devices use -- regardless of device type, you will get data in a single
+well-documented format. Third: on operating systems with a hotplug
+facility (like Linux udev), GPSD will handle all the device
+management as USB devices are plugged in and unplugged.
+
+What GPSD can't do is pull fix data out of thin air when your
+device hasn't reported any. Nor is it a magic power supply,
+so its device management has to be designed around keeping the
+attached sensors open only when a client application actually
+needs a fix.
+
+As you'll see, these constraints explain most of the design of the GPSD
+wire protocol, and of the library APIs your client application
+will be using.
+
+== How the GPSD wire protocol works ==
+
+While GPSD project ships several library bindings that will hide the
+details of the wire protocol from you, you'll understand the library APIs
+better by knowing what a wire-protocol session looks like. After
+reading this section, you can forget the details about commands and
+responses and attributes as long as you hold on to the basic
+logical flow of a session.
+
+Your client library's open function is going to connect a socket to
+port 2947 on the host your sensors are attached to, usually
+localhost. On connection, the gpsd daemon will ship a banner that
+looks something like this:
+
+-----------------------------------------------------------------------------
+{"class":"VERSION","release":"2.93","rev":"2010-03-30T12:18:17",
+ "proto_major":3,"proto_minor":2}
+-----------------------------------------------------------------------------
+
+There's nothing mysterious here. Your server daemon is identifying
+itself with information that may allow a client library to work
+around bugs or potential incompatibilities produced by upgrades.
+
+To get data from the attached sensors, you need to explicitly tell the
+daemon you want it. (Remember that it's trying to minimize the amount
+of time the devices are held open and in a fully powered state.) You
+do this by issuing a WATCH command:
+
+-----------------------------------------------------------------------------
+?WATCH={"enable":true,"json":true}
+-----------------------------------------------------------------------------
+
+This tells the daemon to watch all devices and to issue reports in
+JSON. It can ship some other protocols as well (notably, NMEA 0183)
+but JSON is the most capable and usually what you want.
+
+A side effect of the WATCH command is that the daemon will ship you
+back some information on available devices.
+
+-----------------------------------------------------------------------------
+{"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyUSB0",
+ "activated":1269959537.20,"native":0,"bps":4800,"parity":"N",
+ "stopbits":1,"cycle":1.00}]}
+{"class":"WATCH","enable":true,"json":true,"nmea":false,"raw":0,
+ "scaled":false,"timing":false,"pps":false}
+-----------------------------------------------------------------------------
+
+The DEVICES response tells you what devices are available to the
+daemon; this list is maintained in a way you as the application
+designer don't have to care about. The WATCH response will
+immediately follow and tells you what all your watch request settings
+are.
+
+Up to this point, nothing has been dependent on the state of the
+sensors. At this time, it may well be that none of those devices is
+fully powered up yet. In fact, they won't be, unless another
+GPSD-enabled application is already watching when you open your
+connection. If that's the case, you will start seeing data
+immediately.
+
+For now, though, let's go back to the case where gpsd has to fire up
+the sensors. After issuing the WATCH response, the daemon opens all of
+them and watches for incoming packets that it can recognize. *After
+a variable delay*, it will ship a notification that looks something
+like this:
+
+-----------------------------------------------------------------------------
+{"class":"DEVICE","path":"/dev/ttyUSB0","activated":1269960793.97,
+ "driver":"SiRF binary","native":1,"bps":4800,
+ "parity":"N","stopbits":1,"cycle":1.00}
+-----------------------------------------------------------------------------
+
+This is the daemon telling you that it has recognized a SiRF binary
+GPS on /dev/ttyUSB0 shipping report packets at 4800 bits per second.
+This notification is not delayed by the time it takes to achieve
+satellite lock; the GPS will cheerfully ship packets before that. But
+it will be delayed by the time required for the daemon to sync up with
+the GPS.
+
+The GPSD daemon is designed so it doesn't have to know anything about the
+sensor in advance - not which of a dozen reporting protocols it uses,
+and not even the baud rate of the serial device. The reason for this
+agnosticism is so the daemon can adapt properly to anything a hotplug
+event night throw at it. If you unplug your GPS while your
+application is running, and then plug one one of a different type, the
+daemon will cope. Your application won't know the difference unless
+you have told it to notice device types.
+
+You can even start your application, have it issue a WATCH, realize
+you forgot to plug in a GPS, and do that. The hotplug event will
+tell gpsd, which will add the new device to the watched-devices list
+of every client that has issued a ?WATCH.
+
+In order to make this work, gpsd has a packet sniffer inside it that
+does autobauding and packet-protocol detection. Normally the packet
+sniffer will achieve sync in well under a second (my measured times
+range from 0.10 to 0.53 sec at 4800bps), but it can take longer if
+your serial traffic is degraded by dodgy cables or electrical noise,
+or if the GPS is configured to run at an unusual speed/parity/stopbit
+configuration.
+
+The real point here is that the delay is *variable*. The client
+library, and your application, can't assume a neat lockstep of
+request and instant response.
+
+Once you do get your device(s) synced, things become more predictable.
+The sensor will start shipping fix reports at a constant interval,
+usually every second, and the daemon will massage them into JSON and
+pass them up the client to your application.
+
+However, until the sensor achieves satellite lock, those fixes will be
+"mode 1" - no valid data (mode 2 is a 2D fix, mode 3 is a 3D fix).
+Here's what that looks like:
+
+-----------------------------------------------------------------------------
+{"class":"TPV","device":"/dev/ttyUSB0",
+ "time":"2010-04-30T11:47:43.28Z","ept":0.005,"mode":1}
+-----------------------------------------------------------------------------
+
+Occasionally you'll get another kind of sentence, SKY, that reports a
+satellite skyview. But TPV is the important one. Here's what it
+looks like when the sensor has a fix to report:
+
+-----------------------------------------------------------------------------
+{"class":"TPV","time":"2010-04-30T11:48:20.10Z","ept":0.005,
+ "lat":46.498204497,"lon":7.568061439,"alt":1327.689,
+ "epx":15.319,"epy":17.054,"epv":124.484,"track":10.3797,
+ "speed":0.091,"climb":-0.085,"eps":34.11,"mode":3}
+-----------------------------------------------------------------------------
+
+Note the "mode":3 at the end. This is how you tell that the GPS is
+reporting a full 3D fix with altitude.
+
+If you have an AIS receiver attached, it too will have been opened
+and autobauded and protocol-sniffed after your WATCH. The stream of
+JSON objects will then include things like this:
+
+-----------------------------------------------------------------------------
+{"class":"AIS","type":5,"repeat":0,"mmsi":351759000,"scaled":true,
+ "imo":9134270,"ais_version":0,"callsign":"3FOF8",
+ "shipname":"EVER DIADEM",
+ "shiptype":"Cargo - all ships of this type",
+ "to_bow":225,
+ "to_stern":70,"to_port":1,"to_starboard":31,"draught":12.2,
+ "epfd":"GPS","eta":"05-15T14:00Z",
+ "destination":"NEW YORK","dte":0}
+-----------------------------------------------------------------------------
+
+When your application shuts down, it can cancel its watch:
+
+-----------------------------------------------------------------------------
+?WATCH={"enable":false}
+-----------------------------------------------------------------------------
+
+This will enable the daemon to close devices and conserve
+power. Supposing you don't do this, the daemon will time out devices
+with no listeners, so canceling your watch is not strictly necessary.
+But it is good manners.
+
+Another way to use the daemon is with the ?POLL command To do this, issue
+
+-----------------------------------------------------------------------------
+?WATCH={"enable":true}
+-----------------------------------------------------------------------------
+
+This activates all devices without enabling streaming of reports. You
+can then say "?POLL;" to poll gpsd's recorded data.
+
+-----------------------------------------------------------------------------
+?POLL;
+{"class":"POLL","time":"2012-04-05T15:00:01.501Z","active":1,
+ "tpv":[{"class":"TPV","device":"/dev/ttyUSB0","mode":3,"time":"2012-04-05T15:00:00.000Z","ept":0.005,"lat":40.035083522,"lon":-75.519982905,"alt":166.145,"epx":9.125,"epy":17.778,"epv":34.134,"track":0.0000,"speed":0.000,"climb":0.000,"eps":36.61}],"gst":[{"class":"GST","device":"/dev/ttyUSB0","time":"1970-01-01T00:00:00.000Z","rms":0.000,"major":0.000,"minor":0.000,"orient":0.000,"lat":0.000,"lon":0.000,"alt":0.000}],
+ "sky":[{"class":"SKY","device":"/dev/ttyUSB0","time":"2012-04-05T15:00:00.000Z","xdop":0.61,"ydop":1.19,"vdop":1.48,"tdop":1.14,"hdop":1.40,"gdop":2.30,"pdop":1.99,"satellites":[{"PRN":26,"el":15,"az":49,"ss":29,"used":true},{"PRN":18,"el":62,"az":315,"ss":31,"used":true},{"PRN":15,"el":60,"az":43,"ss":44,"used":true},{"PRN":21,"el":71,"az":237,"ss":0,"used":false},{"PRN":27,"el":52,"az":94,"ss":40,"used":true},{"PRN":9,"el":48,"az":136,"ss":33,"used":true},{"PRN":22,"el":21,"az":291,"ss":36,"used":true},{"PRN":3,"el":8,"az":303,"ss":25,"used":true}]}]}
+-----------------------------------------------------------------------------
+
+This interface is intended for use with applications like CGI scripts
+that cannot wait on output from the daemon but must poke it into responding.
+
+If you're a clever sort, you're already wondering what the daemon does
+if the application at the other end of the client socket doesn't read data
+out of it as fast as gpsd is shipping it upwards. And the answer is
+this: eventually the socket buffer fills up, a write from the daemon
+throws an error, and the daemon shuts down that client socket.
+
+From the point of view of the application, it reads all the buffered
+data and then gets a read return indicating the socket shutdown. We'll
+return to this in the discussion of client libraries, but the thing
+for you to know right now is that this edge case is actually quite
+difficult to fall afoul of. Total data volume on these sockets is not
+high. As long as your application checks for and reads socket data no
+less often than once a second, you won't -- and a second is a *lot* of
+time in which to come back around your main loop.
+
+== Interfacing from the client side ==
+
+The gpsd daemon exports data in three different ways: via a sockets
+interface, via DBUS broadcasts, and via a shared-memory interface,
+It is possible one or more of these may be configured out in your
+installation.
+
+=== The sockets interface ===
+
+The GPSD project provides client-side libraries in C, C++, and Python
+that exercise the sockets export. A Perl module is separately
+available from CPAN. While the details of these libraries vary, they
+all have the same two purposes and the same limitations.
+
+One purpose of the libraries is to handle the details of unpacking
+JSON-based wire-protocol objects into whatever native structure/record
+feature your application language has. This is particularly important
+in the C and C++ libraries, because those languages don't have
+good native support for JSON.
+
+Another purpose is to hide the details of the wire protocol from the
+application. This gives the GPSD developers room to improve extend
+the protocol without breaking every client application. Depend
+on wire-protocol details only at your own risk!
+
+The limitations the libraries have to cope with are the nature of
+the data flow from the sensors, and the simple fact that they're
+not necessarily delivering fixes at any given time.
+
+For details of the libraries' APIs, see their reference
+documentation; the objective of the rest of this section is to teach
+you the general model of client-side interfacing that they all have to
+follow because of the way the daemon works.
+
+Each library has the following entry points:
+
+* Open a session socket to the daemon. Named something like "open()".
+
+* Set watch policy. Named something like "stream()"
+
+* Send wire-protocol commands to the daemon. Deprecated; makes your
+ code dependent on the wire protocol. There is no longer a real
+ use case for this entry point; if you think you need no use it,
+ you have probably failed to understand the rest of the interface.
+
+* Blocking check to see if data from the daemon is waiting. Named
+ something like "waiting()" and taking a wait timeout as argument.
+ Note that choosing a wait timeout of less than twice the cycle time
+ of your device will be hazardous, as the receiver will probably not
+ supply input often enough to prevent a spurious error indication.
+ For the typical 1-second cycle time of GPSes this implies a minimum
+ 2-second timeout.
+
+* Blocking read for data from the daemon. Named something like "read()"
+ (this was "poll()" in older versions).
+
+* Close the session socket. Named something like "close()".
+
+* Enable debugging trace messages
+
+The fact that the data-waiting check and the read both block means
+that, if your application has to deal with other input sources than
+the GPS, you will probably have to isolate the read loop in a thread with
+a mutex lock on the gps_data structure.
+
+Here is a complete table of the binding entry points:
+
+.Entry points in client bindings
+[frame="topbot",options="header"]
+|========================================================================
+|C |C++ |Python |
+Function
+|gps_open() |gpsmm.gpsmm() |gps.\_\_init__() |
+In OO languages the client class initializer opens the daemon socket.
+|gps_send() |gpsmm.send() |gps.send() |
+Send wire-protocol commands to the daemon. Deprecated and unstable.
+|gps_stream() |gpsmm.stream() |gps.stream() |
+Set watch policy. What you should use instead of send().
+|gps_waiting() |gpsmm.waiting() |gps.waiting() |
+Blocking check with timeout to see if input is waiting.
+|gps_read() |gpsmm.read() |gps.read() |
+Blocking read for data from the daemon.
+|gps_unpack() | |gps.unpack() |
+Parse JSON from a specified buffer into a session structure
+|gps_close() |gpsmm.~gpsmm() |gps.close() |
+Close the daemon socket and end the session.
+|gps_data() |gpsmm.data() |gps.data() |
+Get the contents of the client buffer.
+|gps_enable_debug() |gpsmm_enable_debug() | |
+Enable debug tracing. Only useful for GPSD developers.
+|gps_clear_fix() |gpsmm.clear_fix() | |
+Clear the contents of the fix structure.
+|========================================================================
+
+The tricky part is interpreting what you get from the blocking
+read. The reason it's tricky is that you're not guaranteed that
+every read will pick up exactly one complete JSON object from the
+daemon. It may grab one response object, or more than one, or
+part of one, or one or more followed by a fragment.
+
+What the library does on each read is this: get what it can from the
+socket, append that to a private buffer, and then consume as many JSON
+objects from the front of the buffer as it can. Any incomplete JSON
+is left in the private buffer to be completed and unpacked on a later
+go-round.
+
+In C, the library "consumes" a JSON object by unpacking its content
+into a blackboard structure passed to the read entry point by
+address. The structure contains a state-flag mask that you can (and
+should!) check so you'll know which parts of the structure contain
+valid data. It is safe to do nothing unless the PACKET_SET mask bit
+is on, which is the library's way of telling you that at least one
+complete JSON response has arrived since the last read.
+
+Data may accumulate on the blackboard over multiple reads,
+with new TPV reports overwriting old ones; it is guaranteed that
+overwrites are not partial. Expect this pattern to be replicated
+in any compiled language with only fixed-extent structures.
+
+In Python and Perl the read entry point returns an object containing
+accumulated data. The state-flag mask is still useful for telling you
+which parts contain data, and there is still a PACKET_SET bit. Expect
+this pattern to be replicated in other dynamic OO languages when we
+support them.
+
+The C++ binding is a very thin wrapper around the C. You get back an
+object, but it's just a reference to the C blackboard structure. There's
+no unpack() method because it doesn't fit the gpsmm object's RAII model.
+
+All bindings will throw a recognizable error from the read entry
+point when the socket is closed from the daemon side.
+
+[WARNING]
+The timing of your read loop is important. When it has satellite lock,
+the daemon will be writing into its end of the socket once per
+whatever the normal reporting-cycle time of your device is - for a GPS
+normally one peer second. *You must poll the socket more often that
+that.*
+
+If necessary, spawn a worker thread to do this, mutex-locking the
+structure where it outs the reports. If you don't do this, data
+will back up in your socket buffers and position reports will be
+more and more delayed until the socket FIFO fills, at which point the
+daemon will conclude the client has died and drop the connection.
+
+AIVDM clients have a longer maximum allowable poll interval, but a
+problem of a different kind. you have the problem that later sentences
+of (say) Type 1 don't obsolete the data in earlier ones. This is a
+problem, because the library is designed so that read calls pull any
+JSON reports waiting from the daemon and interpret them all.
+
+To avoid losing data, you want to poll the daemon more often than once
+per two seconds (that being the minimum transmission period for the
+most frequently shipped sentences, Type 1/2/3). That way the read
+buffer will never contain both a message and a later message of the
+same type that steps on it.
+
+=== Shared-memory interface ===
+
+Whenever gpsd recognizes a packet from any attached device, it writes
+the accumulated state from that device to a shared memory segment. The
+C and C++ client libraries shipped with GPSD can read this segment.
+
+The API for reading the segment uses the same gps_open(), gps_read()
+and gps_close() entry points as the sockets interface. To enable using
+shared memory instead, it is only necessary to use the macro constant
+GPSD_SHARED_MEMORY as the host argument of gps_open().
+
+The gps_stream(), gps_send(), gps_waiting(), and gps_data() entry
+points are not available with this interface. You cannot set a device
+filter on it. You will not get device activation or deactivation
+notices through it. And, of course, it is only good for local and not
+networked access. Its main advantage is that it is very fast and
+lightweight, especially suitable for use in low-power embedded
+deployments with a single device on a fixed port and the sockets
+interface configured out.
+
+Under the shared-memory interface, gps_read() after a successful
+gps_open() will always return with data; its return is the size of a
+struct gps_data_t in bytes. The 'gps_fd' member of the struct gpsdata
+instance handed to you will always be -1. The PACKET_SET flag will
+always be asserted. The other flag bits in the 'set' member will tell
+you what data is updated in the instance, just as in the sockets
+interface.
+
+The shared-memory interface is not yet available from Python.
+
+=== D-Bus broadcasts ===
+
+If your system supports D-Bus, gpsd broadcasts a signal with path /org/gpsd,
+interface "org.gpsd", and name "fix" whenever it received a position
+report from any device attached to it. See the gpsd(8) manual page for
+details of the binary payload layout.
+
+== C Examples ==
+
+The source distribution includes two example clients in C;
+gpxlogger.c and cgps.c.
+
+gpxlogger.c illustrates the simplest possible program flow; open,
+followed by stream, followed by the library main loop.
+
+cgps.c shows what an interactive application using the library and
+also hw processing user commands works. Note the use of the curses
+nodelay function to ensure that wgetch() does not block the GPS
+polling loop.
+
+== C++ examples ==
+
+The following code skeleton implements a C++ client:
+
+----------------------------------------------------------------------
+
+int main(void)
+{
+ gpsmm gps_rec("localhost", DEFAULT_GPSD_PORT);
+
+ if (gps_rec.stream(WATCH_ENABLE|WATCH_JSON) == NULL) {
+ cerr << "No GPSD running.\n";
+ return 1;
+ }
+
+ for (;;) {
+ struct gps_data_t* newdata;
+
+ if (!gps_rec.waiting(50000000))
+ continue;
+
+ if ((newdata = gps_rec.read()) == NULL) {
+ cerr << "Read error.\n";
+ return 1;
+ } else {
+ PROCESS(newdata);
+ }
+ }
+ return 0;
+}
+
+----------------------------------------------------------------------
+
+Note the absence of explicit open and close methods. The object
+interface is designed on the RAII (Resource Acquisition Is
+Initialization) model; you close it by deallocating it.
+
+Look at test_gpsmm.cpp in the distribution for a full example.
+
+== Python examples ==
+
+There's a very simple Python example analogous to gpxlogger attached
+to the source code for the gps.py library.
+
+The heart of it is this code:
+
+-----------------------------------------------------------------------------
+ session = gps(**opts)
+ session.stream(WATCH_ENABLE|WATCH_NEWSTYLE)
+ for report in session:
+ print report
+-----------------------------------------------------------------------------
+
+If you need to intersperse other processing in a main event loop,
+like this:
+
+----------------------------------------------------------------------
+
+session = gps(mode=WATCH_ENABLE)
+try:
+ while True:
+ # Do stuff
+ report = session.next()
+ # Check report class for 'DEVICE' messages from gpsd. If
+ # we're expecting messages from multiple devices we should
+ # inspect the message to determine which device
+ # has just become available. But if we're just listening
+ # to a single device, this may do.
+ if report['class'] == 'DEVICE':
+ # Clean up our current connection.
+ session.close()
+ # Tell gpsd we're ready to receive messages.
+ session = gps(mode=WATCH_ENABLE)
+ # Do more stuff
+except StopIteration:
+ print "GPSD has terminated"
+
+----------------------------------------------------------------------
+
+Each call to the iterator yields a report structure until the daemon
+terminates, at which point the iterator next() method will raise
+StopIteration and the loop will terminate.
+
+The report object returned by next() can be accessed either as a dictionary
+or as an object. As a dictionary, it is the raw contents of the last
+JSON response re-encoded in plain ASCII. For convenience, you may
+also access it as an object with members for each attribute in the
+dictionary. It is especially useful to know that the object will
+always have a "class" member giving the response type (TPV, SKY,
+DEVICE, etc.) as a string.
+
+For more interesting examples integrated with X and GTK, see xgps and
+xgpsspeed.
+
+== Other Client Bindings ==
+
+There are a couple of client bindings for GPSD that are maintained
+separately from the GPSD distribution. We don't try to document their
+APIs here, but just provide pointers to them.
+
+== Java ==
+
+There is a Java binding, described at http://gpsd4java.forge.hoegergroup.de/
+This binding is available at maven central. See that web page for how
+to use it in a maven build.
+
+== Perl ==
+
+There's a Perl client library at http://search.cpan.org/dist/Net-GPSD3/
+
+== Backward Incompatibility and Future Changes ==
+
+The C/C++ binding makes available two preprocessor symbols,
+GPSD_API_MAJOR_VERSION and GPSD_API_MINOR_VERSION, in gps.h.
+The Python module has corresponding symbols.
+
+In major versions before 5:
+
+* gps_open() didn't take a third argument; instead, it returned malloc storage.
+
+* The 'read()' method in various bindings was named 'poll()', blocked
+ waiting for input, and had a different return convention. The name
+ 'poll()' will at some point be reintroduced as an interface to the
+ wire-protocol POLL command.
+
+* Clients needed to define a hook for client-side logging if they
+ didn't want code in netlib.c and libgps_core.c to occasionally send
+ messages to stderr. This requirement is now gone.
+
+* There was a set_raw_hook() method in the C and Python bindings, now gone.
+ C clients should call gps_data(); the buffer is available directly in Python,
+ both as str (response) and bytes (bresponse). The distinction matters
+ in Python 3.
+
+//end