summaryrefslogtreecommitdiff
path: root/gps.py
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2009-08-14 20:48:21 +0000
committerEric S. Raymond <esr@thyrsus.com>2009-08-14 20:48:21 +0000
commitd7a3bb12a37868b2b38ce25ffd15fb9b60c874cb (patch)
treef64e9a50b1e9b56d8bb64cea8b2ab60364d5101e /gps.py
parentb5a1749e742af9b1be39d4924dcf0d4952a57ade (diff)
downloadgpsd-d7a3bb12a37868b2b38ce25ffd15fb9b60c874cb.tar.gz
Back out recent breakage in the Python binding that didn't work.
Back out bzed's major change of 26 May and three related later changes by esr on 13 Aug, all in gps.py. These introduced a serious bug - all pending responses read were unpacked, but *only the last response* in any given group was available after the return of the poll() call. This broke gpsfake, a problem which was concealed by a thinko in the regression-test driver. The client falling behind the daemon is still an issue, but needs to be tackled in a different way.
Diffstat (limited to 'gps.py')
-rwxr-xr-xgps.py105
1 files changed, 33 insertions, 72 deletions
diff --git a/gps.py b/gps.py
index 76cc05e5..3e3aca9b 100755
--- a/gps.py
+++ b/gps.py
@@ -186,8 +186,7 @@ class gps(gpsdata):
def __init__(self, host="127.0.0.1", port="2947", verbose=0):
gpsdata.__init__(self)
self.sock = None # in case we blow up in connect
- self.eof = False
- self.buf = ''
+ self.sockfile = None
self.connect(host, port)
self.verbose = verbose
self.raw_hook = None
@@ -210,12 +209,14 @@ class gps(gpsdata):
#if self.debuglevel > 0: print 'connect:', (host, port)
msg = "getaddrinfo returns an empty list"
self.sock = None
+ self.sockfile = None
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
self.sock = socket.socket(af, socktype, proto)
#if self.debuglevel > 0: print 'connect:', (host, port)
self.sock.connect(sa)
+ self.sockfile = self.sock.makefile()
except socket.error, msg:
#if self.debuglevel > 0: print 'connect fail:', (host, port)
self.close()
@@ -228,15 +229,18 @@ class gps(gpsdata):
self.raw_hook = hook
def close(self):
+ if self.sockfile:
+ self.sockfile.close()
if self.sock:
self.sock.close()
self.sock = None
+ self.sockfile = None
def __del__(self):
self.close()
def __unpack(self, buf):
- """Unpack a daemon response into the instance members"""
+ # unpack a daemon response into the instance members
self.fix.time = 0.0
fields = buf.strip().split(",")
if fields[0] == "GPSD":
@@ -369,85 +373,42 @@ class gps(gpsdata):
self.raw_hook(buf);
def waiting(self):
- """Return True if data is ready for the client."""
- try:
- (winput, woutput, wexceptions) = select.select([self.sock], [], [], 0)
- except select.error, socket.error:
- self.eof = True
- return False
- return len(winput) > 0
-
- def readlines(self):
- """Yield the next few complete lines. If no data is available,
- return an empty string."""
- if self.eof or not self.waiting():
- yield ''
- # Accumulate input
- while self.waiting():
- buf = self.sock.recv(512)
- if buf:
- self.buf += buf
- else:
- self.eof = True
- break
- lines = self.buf.split('\r\n')
- if lines and not lines[-1]:
- lines.pop()
- # Now yield it line by line
- for l in lines[:]:
- if l:
- yield l + "\r\n"
- del lines[0]
-
- def readstanzas(self):
- """Read a possibly multi-line response.
- Currently used for RTCM2 H responses."""
- stanza = []
- for frag in self.readlines():
- if self.eof:
- yield ''
- if frag:
- # Old-style protocol line or raw GPS data or JSON object
- if '=' in frag or frag[0] in "!${":
- yield frag
- stanza = []
- # End of Sager-format RTCM2 dump
- elif frag == '.':
- yield '\r\n'.join(stanza)
- stanza = []
- # Body of Sager-format RTCM2 dump
- else:
- stanza.append(frag)
+ "Return True if data is ready for the client."
+ (winput, woutput, wexceptions) = select.select((self.sock,), (), (), 0)
+ return winput != []
def poll(self):
- """Wait for and read data being streamed from gpsd.
- Return values: -1 on EOF, 1 on no more data, 0 otherwise"""
- for self.response in self.readstanzas():
- if self.eof:
- return -1
- if not self.response:
- return 1
- if self.verbose:
- sys.stderr.write("GPS DATA %s\n" % `self.response`)
- self.timings.c_recv_time = time.time()
- self.__unpack(self.response)
- if self.profiling:
- if self.timings.sentence_time != '?':
- basetime = self.timings.sentence_time
- else:
- basetime = self.timings.d_xmit_time
- self.timings.c_decode_time = time.time() - basetime
- self.timings.c_recv_time -= basetime
+ "Wait for and read data being streamed from gpsd."
+ self.response = self.sockfile.readline()
+ if self.response.startswith("H") and "=" not in self.response:
+ while True:
+ frag = self.sockfile.readline()
+ self.response += frag
+ if frag.startswith("."):
+ break
+ if not self.response:
+ return -1
+ if self.verbose:
+ sys.stderr.write("GPS DATA %s\n" % repr(self.response))
+ self.timings.c_recv_time = time.time()
+ self.__unpack(self.response)
+ if self.profiling:
+ if self.timings.sentence_time != '?':
+ basetime = self.timings.sentence_time
+ else:
+ basetime = self.timings.d_xmit_time
+ self.timings.c_decode_time = time.time() - basetime
+ self.timings.c_recv_time -= basetime
return 0
def send(self, commands):
- """Ship commands to the daemon."""
+ "Ship commands to the daemon."
if not commands.endswith("\n"):
commands += "\n"
self.sock.send(commands)
def query(self, commands):
- """Send a command, get back a response."""
+ "Send a command, get back a response."
self.send(commands)
return self.poll()