3 # gpsfake -- test harness for gpsd
5 # Simulates a GPS, playing back a logfile
6 # Most of the logic for this now lives in gps.fake,
7 # factored out so we can write other test programs with it.
9 # This file is Copyright (c) 2010 by the GPSD project
10 # BSD terms apply: see the file COPYING in the distribution root for details.
12 import sys, os, signal, time, getopt, socket, random
16 "Ship progress indications to stderr."
17 def __init__(self, prompt, endmsg=None):
18 self.stream = sys.stderr
19 self.stream.write(prompt + "...")
20 if os.isatty(self.stream.fileno()):
21 self.stream.write(" \010")
25 self.time = time.time()
28 def twirl(self, ch=None):
29 if self.stream is None:
31 if os.isatty(self.stream.fileno()):
35 self.stream.write("-/|\\"[self.count % 4])
36 self.stream.write("\010")
38 self.count = self.count + 1
41 def end(self, msg=None):
45 self.stream.write("...(%2.2f sec) %s.\n" % (time.time() - self.time, msg))
49 "Find a port that isn't in use to bind to."
50 # Grab a random port from IANA's unassigned/private range. Not perfect,
51 # but at least less than in 16000 chance of a pair collision. It would
52 # be very hard to get this deterministically correct, since there would
53 # always be a window between port allocation and when the daemon picked
54 # it up. We'd need to do some kind of semaphore, etc., and even that
55 # wouldn't prevent collisions with other apps using the range.
56 return random.randint(49152, 65535)
61 rep += "%02x" % ord(c)
64 def fakehook(linenumber, fakegps):
65 if len(fakegps.testload.sentences) == 0:
66 print >>sys.stderr, "fakegps: no sentences in test load."
68 if linenumber % len(fakegps.testload.sentences) == 0:
69 if singleshot and linenumber > 0:
74 sys.stderr.write("gpsfake: log cycle of %s begins.\n" % fakegps.testload.name)
76 if linedump and fakegps.testload.legend:
77 ml = fakegps.testload.sentences[linenumber % len(fakegps.testload.sentences)].strip()
78 if not fakegps.testload.textual:
80 announce = fakegps.testload.legend % (linenumber % len(fakegps.testload.sentences) + 1) + ml
82 raw_input(announce + "? ")
89 if __name__ == '__main__':
91 (options, arguments) = getopt.getopt(sys.argv[1:], "1bc:D:fghilm:no:pr:s:uvx")
92 except getopt.GetoptError, msg:
93 print "gpsfake: " + str(msg)
97 print >>sys.stderr, "gpsfake: requires at least one logfile argument."
110 client_init = '?WATCH={"json":true,"nmea":true}'
114 for (switch, val) in options:
118 elif (switch == '-b'):
120 elif (switch == '-c'):
122 elif (switch == '-D'):
123 doptions += " -D " + val
124 elif (switch == '-g'):
125 monitor = "xterm -e gdb -tui --args "
126 elif (switch == '-i'):
127 linedump = promptme = True
128 elif (switch == '-l'):
130 elif (switch == '-m'):
132 elif (switch == '-n'):
134 elif (switch == '-x'):
136 elif (switch == '-o'):
138 elif (switch == '-p'):
140 elif (switch == '-r'):
142 elif (switch == '-s'):
144 elif (switch == '-u'):
146 elif (switch == '-v'):
148 elif (switch == '-h'):
149 sys.stderr.write("usage: gpsfake [-h] [-l] [-m monitor] [--D debug] [-o options] [-p] [-s speed] [-c cycle] [-b] logfile\n")
153 baton = Baton("Processing %s" % ",".join(arguments), "done")
155 print >>sys.stderr, "Processing %s" % ",".join(arguments)
157 test = gps.fake.TestSession(prefix=monitor, port=port, options=doptions, udp=udp, verbose=verbose, predump=predump)
160 test.reporter = sys.stdout.write
163 test.progress = sys.stdout.write
166 for logfile in arguments:
168 test.gps_add(logfile, speed=speed, pred=fakehook)
169 except gps.fake.TestLoadError, e:
170 sys.stderr.write("gpsfake: " + e.msg + "\n")
172 except gps.fake.PacketError, e:
173 sys.stderr.write("gpsfake: " + e.msg + "\n")
175 except gps.fake.DaemonError, e:
176 sys.stderr.write("gpsfake: " + e.msg + "\n")
179 sys.stderr.write("gpsfake: no such file as %s or file unreadable\n"%e.filename)
182 sys.stderr.write("gpsfake: can't open pty.\n")
187 test.client_add(client_init + "\n")
188 # Give daemon time to get ready for the feeds.
189 # Without a delay here there's a window for test
190 # sentences to arrive before the watch takes effect.
191 # This needs to increase if leading sentences in
192 # test loads aren't being processed.
195 except socket.error, msg:
196 sys.stderr.write("gpsfake: socket error %s.\n" % msg)
204 # The following sets edit modes for GNU EMACS