1
2
3
4 import time, socket, sys, select
5
6 if sys.hexversion >= 0x2060000:
7 import json
8 else:
9 import simplejson as json
10
11 GPSD_PORT="2947"
12
14 "Isolate socket handling and buffering from the protcol interpretation."
20
22 """Connect to a host on a given port.
23
24 If the hostname ends with a colon (`:') followed by a number, and
25 there is no port specified, that suffix will be stripped off and the
26 number interpreted as the port number to use.
27 """
28 if not port and (host.find(':') == host.rfind(':')):
29 i = host.rfind(':')
30 if i >= 0:
31 host, port = host[:i], host[i+1:]
32 try: port = int(port)
33 except ValueError:
34 raise socket.error, "nonnumeric port"
35
36
37 msg = "getaddrinfo returns an empty list"
38 self.sock = None
39 for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
40 af, socktype, proto, canonname, sa = res
41 try:
42 self.sock = socket.socket(af, socktype, proto)
43
44 self.sock.connect(sa)
45 except socket.error, msg:
46
47 self.close()
48 continue
49 break
50 if not self.sock:
51 raise socket.error, msg
52
54 if self.sock:
55 self.sock.close()
56 self.sock = None
57
60
62 "Return True if data is ready for the client."
63 if self.linebuffer:
64 return True
65 (winput, woutput, wexceptions) = select.select((self.sock,), (), (), 0)
66 return winput != []
67
69 "Wait for and read data being streamed from the daemon."
70 if self.verbose > 1:
71 sys.stderr.write("poll: reading from daemon...\n")
72 eol = self.linebuffer.find('\n')
73 if eol == -1:
74 frag = self.sock.recv(4096)
75 self.linebuffer += frag
76 if self.verbose > 1:
77 sys.stderr.write("poll: read complete.\n")
78 if not self.linebuffer:
79 if self.verbose > 1:
80 sys.stderr.write("poll: returning -1.\n")
81
82 return -1
83 eol = self.linebuffer.find('\n')
84 if eol == -1:
85 if self.verbose > 1:
86 sys.stderr.write("poll: returning 0.\n")
87
88 return 0
89 else:
90 if self.verbose > 1:
91 sys.stderr.write("poll: fetching from buffer.\n")
92
93
94 eol += 1
95 self.response = self.linebuffer[:eol]
96 self.linebuffer = self.linebuffer[eol:]
97
98
99 if not self.response:
100 return -1
101 if self.verbose:
102 sys.stderr.write("poll: data is %s\n" % repr(self.response))
103 self.received = time.time()
104
105 return len(self.response)
106
107 - def send(self, commands):
108 "Ship commands to the daemon."
109 if not commands.endswith("\n"):
110 commands += "\n"
111 self.sock.send(commands)
112
113 WATCH_DISABLE = 0x0000
114 WATCH_ENABLE = 0x0001
115 WATCH_JSON = 0x0002
116 WATCH_NMEA = 0x0004
117 WATCH_RARE = 0x0008
118 WATCH_RAW = 0x0010
119 WATCH_SCALED = 0x0020
120 WATCH_DEVICE = 0x0040
121
123 "Basic JSON decoding."
126
128 def asciify(d):
129 "De-Unicodify everything so we can copy dicts into Python objects."
130 t = {}
131 for (k, v) in d.items():
132 ka = k.encode("ascii")
133 if type(v) == type(u"x"):
134 va = v.encode("ascii")
135 elif type(v) == type({}):
136 va = asciify(v)
137 elif type(v) == type([]):
138 va = map(asciify, v)
139 else:
140 va = v
141 t[ka] = va
142 return t
143 self.data = dictwrapper(**asciify(json.loads(buf.strip(), encoding="ascii")))
144
145 if self.data["class"] == "SKY" and hasattr(self.data, "satellites"):
146 self.data.satellites = map(lambda x: dictwrapper(**x), self.data.satellites)
147
148 - def stream(self, flags=0, outfile=None):
149 "Control streaming reports from the daemon,"
150 if flags & WATCH_DISABLE:
151 arg = '?WATCH={"enable":false'
152 if flags & WATCH_JSON:
153 arg += ',"json":false'
154 if flags & WATCH_NMEA:
155 arg += ',"nmea":false'
156 if flags & WATCH_RARE:
157 arg += ',"raw":1'
158 if flags & WATCH_RAW:
159 arg += ',"raw":2'
160 if flags & WATCH_SCALED:
161 arg += ',"scaled":false'
162 else:
163 arg = '?WATCH={"enable":true'
164 if flags & WATCH_JSON:
165 arg += ',"json":true'
166 if flags & WATCH_NMEA:
167 arg += ',"nmea":true'
168 if flags & WATCH_RAW:
169 arg += ',"raw":1'
170 if flags & WATCH_RARE:
171 arg += ',"raw":0'
172 if flags & WATCH_SCALED:
173 arg += ',"scaled":true'
174 if flags & WATCH_DEVICE:
175 arg += ',"device":"%s"' % outfile
176 return self.send(arg + "}")
177
179 "Wrapper that yields both class and dictionary behavior,"
181 self.__dict__ = ddict
182 - def get(self, k, d=None):
183 return self.__dict__.get(k, d)
185 return self.__dict__.keys()
187 "Emulate dictionary, for new-style interface."
188 return self.__dict__[key]
190 "Emulate dictionary, for new-style interface."
191 self.__dict__[key] = val
193 return key in self.__dict__
195 return "<dictwrapper: " + str(self.__dict__) + ">"
196 __repr__ = __str__
197
198
199
200
201
202
203