summaryrefslogtreecommitdiff
path: root/HACKING
blob: 156061bec2c31d913204d6ebf1615bbf4fa739e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
			Hacker's Guide to gpsd

First, debugging...

For debugging purposes, it may be helpful to configure with --disable-shared.
This turns off all the shared-library crud, making it somewhat easier to
use gdb.

There is a script called logextract in the distribution that you can use
to strip clean NMEA out of the log files produced by gpsd.  This can be
useful if someone ships you a log that they allege caused gpsd to 
misbehave.

Next, profiling...

If you build with --enable-profiling, an undocumented Z command in the daemon 
will cause it to emit a $ clause on every D request.  The $ clause contains
two colon-separated fields: a millisecond-precision timestamp telling when
gpsd shipped the data, and the character length of the sentence containing the 
timestamp data (a GPRMC, GPLL, or GPGGA sentence).

The spread between D and Z timestamps measures the latency between the
GPS's fix measurement and when it became available to the client. For
it to be meaningful, the GPS has to ship timestamps with sub-second
precision. SiRF-II and Evermore chipsets ship times with millisecond
resolution.  Your machine's time reference must also be accurate to
subsecond precision; I recommend using ntpd, which will normally give
you about 15 microseconds precision (two orders of magnitude better than 
GPSes normally report).

Another helpful command is B.  Without arguments, it triggers a response
of the form <baudrate> <bits> N <stopbits>, e.g. "4800 8 N 1" describing
the communications parameters of the link to the GPS.  If profiling is 
enabled, B may be followed by an equals sign and a baud rate; the link
will then change to that rate.  This feature is not enabled by default
because it is not secured and can be used to effectively disable the GPS.

The distribution lincludes a Python script, gpsprof, that uses the 
Z command to collect profiling information from a running GPS instance.
You can use this to measure the latency at each stage -- GPS to daemon,
daemon to client library -- and to estimate the portion of the latency 
induced by serial transmit time.  The gpsprof script creates latency
plots using gnuplot(1).  It can also report the raw data.

Then, architecture and how to hack it...

This is not a complicated piece of code.  Essentially, it spins in a loop 
polling for input from one of three sources:

1) A client making requests over a TCP/IP port.

2) The GPS, connected via serial or USB device.

3) A DGPS server issuing periodic differential-GPS updates.

The daemon only connects to the GPS when clients are connected to it.
Otherwise the GPS device is closed and the daemon is quiescent, but
retains fix and timestamp data from the last active period.  This is
better functional design than starting the daemon from a hotplug
script would be; that would lose the old data, leaving no fix at all
available if the GPS were momentarily unplugged.

All writes to client sockets go through throttled_write().
This code addresses two cases.  First, client has dropped the connection.
Second, client is connected but not picking up data and our buffers are
backing up.  If we let this continue, the write buffers will fill and 
the effect will be denial-of-service to clients that are better behaved.

Our strategy is brutally simple and takes advantage of the fact that
GPS data has a short shelf life.  If the client doesn't pick it up 
within a few minutes, it's probably not useful to that client.  So if
data is backing up to a client, drop that client.  That's why we set
the client socket to nonblocking.

GPS input updates an internal data structure which has slots in it for
all the data you can get from a GPS.  Client commands mine that
structure and ship reports up the socket to the client.  DGPS data is
passed through, raw, to the GPS.

The trickiest part of the code is the handling of input sources in gpsd.c 
itself.  It had to tolerate clients connecting and disconnecting at random
times, and the GPS being unplugged and replugged, without leaking file 
descriptors; also arrange for the GPS to be open when and only when clients 
are active.

The function is_input_waiting() is not strictly necessary for the most
important use of the low-level interface, which is when it gets called
from the daemon mainline.  In that context, FD_ISSET() on the element
of the file-descriptor set representing the GPS would tell us if there
were input waiting.  The explicit test is there for other programs
that might call gps_poll() without such a guarantee.

That's about all there is to it.

Adding new GPS types...

Almost all GPSes speak NMEA 0183.  However, it may occasionally be necessary
to add support for some odd binary format.  We're told that the hex dump
functions in CuteCom <http://cutecom.sourceforge.net/> can be useful for
investigating such protocols.

Internally, gpsd supports multiple GPS types.  All are represented by
driver method tables; the main loop knows nothing about the driver
methods except when to call them.  At any given time one driver is
active; by default it's the NMEA one.  To add a new device, populate
another driver structure and add it to the list.

Each driver may have a trigger string that the NMEA interpreter
watches for.  When that string is recognized at the start of a 
line, the interpreter switches to its driver.  The new driver 
initializer method is called immediately.  If there is no trigger string
the initializer method is called unconditionally each time the device
is opened.

And more...

If you're looking for things to hack on, first see the TODO file.
Then, there is some C code in the contrib/ directory that has some
potentially useful techniques in it.  Picking a good one to integrate
into gpsd might be a useful thing.