def onconnected(self): #print('connected to pypilot server', time.time()) self.last_values_list = False # write config if connection succeeds try: file = open(self.configfilename, 'w') file.write(pyjson.dumps(self.config) + '\n') file.close() self.write_config = False except IOError: print('failed to write config file:', self.configfilename) except Exception as e: print('Exception writing config file:', self.configfilename, e) self.connection = LineBufferedNonBlockingSocket( self.connection_in_progress, self.config['host']) self.connection_in_progress = False self.poller = select.poll() self.poller.register(self.connection.socket, select.POLLIN) self.wwatches = {} for name, value in self.watches.items(): self.wwatches[name] = value # resend watches self.values.onconnected()
def connect(self): time.sleep(2) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('127.0.0.1', 2947)) self.poller.register(sock, select.POLLIN) sock.settimeout(0) sock.send('?WATCH={"enable":true,"json":true};'.encode()) self.gpsd_socket = LineBufferedNonBlockingSocket(sock, 'gpsd') self.gpsconnecttime = time.monotonic() self.devices = [] print('gpsd connected') #except socket.error: except ConnectionRefusedError: print('gpsd failed to connect') self.gpsd_socket = False time.sleep(30) except Exception as e: self.gpsd_socket = False print('exception connecting to gps', e) time.sleep(60)
def onconnected(self, connection): if self.write_config: try: file = open(self.configfilename, 'w') file.write(kjson.dumps(self.write_config) + '\n') file.close() self.write_config = False except IOError: print 'failed to write config file:', self.configfilename except Exception as e: print 'Exception writing config file:', self.configfilename, e self.socket = LineBufferedNonBlockingSocket(connection) self.values = [] self.msg_queue = [] self.poller = select.poll() if self.socket: fd = self.socket.socket.fileno() else: fd = self.serial.fileno() self.poller.register(fd, select.POLLIN) self.f_on_connected(self)
def PollSockets(self): events = self.poller.poll(0) while events: event = events.pop() fd, flag = event socket = self.fd_to_socket[fd] if socket == self.server_socket: connection, address = socket.accept() if len(self.sockets) == max_connections: print('signalk server: max connections reached!!!', len(self.sockets)) self.RemoveSocket(self.sockets[0]) # dump first socket?? socket = LineBufferedNonBlockingSocket(connection) self.sockets.append(socket) fd = socket.socket.fileno() # print('new client', address, fd) self.fd_to_socket[fd] = socket self.poller.register(fd, select.POLLIN) elif flag & (select.POLLHUP | select.POLLERR | select.POLLNVAL): self.RemoveSocket(socket) elif flag & select.POLLIN: if not socket.recv(): self.RemoveSocket(socket) while True: line = socket.readline() if not line: break try: self.HandleRequest(socket, line) except Exception as e: print('invalid request from socket', line, e) socket.send('invalid request: ' + line + '\n') # flush all sockets for socket in self.sockets: socket.flush()
class pypilotClient(object): def __init__(self, host=False): self.values = ClientValues(self) self.watches = {} self.wwatches = {} self.received = [] self.last_values_list = False if False: self.server = host host = '127.0.0.1' if host and type(host) != type(''): # host is the server object self.server = host self.connection = host.pipe() self.poller = select.poll() fd = self.connection.fileno() if fd: self.poller.register(fd, select.POLLIN) self.values.onconnected() return config = {} try: configfilepath = os.getenv('HOME') + '/.pypilot/' if not os.path.exists(configfilepath): os.makedirs(configfilepath) if not os.path.isdir(configfilepath): raise Exception(configfilepath + 'should be a directory') except Exception as e: print('os not supported') configfilepath = '/.pypilot/' self.configfilename = configfilepath + 'pypilot_client.conf' try: file = open(self.configfilename) config = pyjson.loads(file.readline()) file.close() except Exception as e: print('failed to read config file:', self.configfilename, e) config = {} if host: if ':' in host: i = host.index(':') config['host'] = host[:i] config['port'] = host[i + 1:] else: config['host'] = host if not 'host' in config: config['host'] = '127.0.0.1' if not 'port' in config: config['port'] = DEFAULT_PORT self.config = config self.connection = False # connect later self.connection_in_progress = False def onconnected(self): #print('connected to pypilot server', time.time()) self.last_values_list = False # write config if connection succeeds try: file = open(self.configfilename, 'w') file.write(pyjson.dumps(self.config) + '\n') file.close() self.write_config = False except IOError: print('failed to write config file:', self.configfilename) except Exception as e: print('Exception writing config file:', self.configfilename, e) self.connection = LineBufferedNonBlockingSocket( self.connection_in_progress, self.config['host']) self.connection_in_progress = False self.poller = select.poll() self.poller.register(self.connection.socket, select.POLLIN) self.wwatches = {} for name, value in self.watches.items(): self.wwatches[name] = value # resend watches self.values.onconnected() def poll(self, timeout=0): if not self.connection: if self.connection_in_progress: events = self.poller_in_progress.poll(0) if events: fd, flag = events.pop() if not (flag & select.POLLOUT): # hung hup self.connection_in_progress.close() self.connection_in_progress = False return self.onconnected() return else: if not self.connect(False): time.sleep(timeout) return # inform server of any watches we have changed if self.wwatches: self.connection.write('watch=' + pyjson.dumps(self.wwatches) + '\n') #print('watch', watches, self.wwatches, self.watches) self.wwatches = {} # send any delayed watched values self.values.send_watches() if self.connection.fileno(): # flush output self.connection.flush() try: events = self.poller.poll(int(1000 * timeout)) except Exception as e: print('exception polling', e, os.getpid()) self.disconnect() return if not events: return # no data ready fd, flag = events.pop() if not (flag & select.POLLIN) or (self.connection and not self.connection.recvdata()): # other flags indicate disconnect self.disconnect() # recv returns 0 means connection closed return # read incoming data line by line while True: t0 = time.monotonic() line = self.connection.readline() if not line: return try: name, data = line.rstrip().split('=', 1) if name == 'error': print('server error:', data) continue value = pyjson.loads(data) except ValueError as e: print('client value error:', line, e) #raise Exception continue except Exception as e: print('invalid message from server:', line, e) raise Exception() if name in self.values.values: # did this client register this value self.values.values[name].set(value) else: self.received.append((name, value)) # remote value # polls at least as long as timeout def disconnect(self): if self.connection: self.connection.close() self.connection = False def connect(self, verbose=True): if self.connection: print('warning, client aleady has connection') try: host_port = self.config['host'], self.config['port'] self.connection_in_progress = False self.connection_in_progress = socket.socket( socket.AF_INET, socket.SOCK_STREAM) self.connection_in_progress.settimeout(1) # set to 0 ? self.connection_in_progress.connect(host_port) except OSError as e: import errno if e.args[0] is errno.EINPROGRESS: self.poller_in_progress = select.poll() self.poller_in_progress.register( self.connection_in_progress.fileno(), select.POLLOUT) return True self.connection_in_progress = False if e.args[0] == 111: # refused pass else: print('connect failed to %s:%d' % host_port, e) #time.sleep(.25) return False #except Exception as e: # if verbose: # print('connect failed to %s:%d' % host_port, e) self.onconnected() return True def receive_single(self): if self.received: ret = self.received[0] self.received = self.received[1:] return ret return False def receive(self, timeout=0): self.poll(timeout) ret = {} for msg in self.received: name, value = msg ret[name] = value self.received = [] return ret def send(self, msg): if self.connection: self.connection.write(msg) def set(self, name, value): # quote strings if type(value) == type('') or type(value) == type(u''): value = '"' + value + '"' elif type(value) == type(True): value = 'true' if value else 'false' self.send(name + '=' + str(value) + '\n') def watch(self, name, value=True): if name in self.watches: # already watching if value is False: del self.watches[name] self.wwatches[name] = value return elif self.watches[name] is value: return # same watch ignore elif value is False: return # already not watching self.watches[name] = value self.wwatches[name] = value def clear_watches(self): for name in self.watches: self.wwatches[name] = False self.watches = {} def register(self, value): self.values.register(value) value.client = self return value def get_values(self): if self.values.value: return self.values.value return {} def list_values(self, timeout=0): self.watch('values') t0, dt, ret = time.monotonic(), timeout, self.values.value while not ret and dt >= 0: self.poll(dt) ret = self.values.value dt = timeout - (time.monotonic() - t0) if self.last_values_list == ret: return False self.last_values_list = ret return ret def info(self, name): return self.values.value[name]
def poll(self, timeout=0): # server is in subprocess if self.process != 'main process': if not self.process: self.init_process() return t0 = time.monotonic() if t0 >= self.values.persistent_timeout: self.values.store() dt = time.monotonic() - t0 if dt > .1: print('persistent store took too long!', time.monotonic() - t0) return if timeout: timeout *= 1000 # milliseconds timeout = .1 events = self.poller.poll(timeout) while events: event = events.pop() fd, flag = event connection = self.fd_to_connection[fd] if connection == self.server_socket: connection, address = connection.accept() if len(self.sockets) == max_connections: print('pypilot server: max connections reached!!!', len(self.sockets)) self.RemoveSocket(self.sockets[0]) # dump first socket?? socket = LineBufferedNonBlockingSocket(connection, address) print('server add socket', socket.address) self.sockets.append(socket) fd = socket.fileno() socket.cwatches = { 'values': True } # server always watches client values self.fd_to_connection[fd] = socket self.poller.register(fd, select.POLLIN) elif flag & (select.POLLHUP | select.POLLERR | select.POLLNVAL): if not connection in self.sockets: print('internal pipe closed, server exiting') exit(0) self.RemoveSocket(connection) elif flag & select.POLLIN: if fd in self.fd_to_pipe: if not connection.recvdata(): continue line = connection.readline( ) # shortcut since poll indicates data is ready while line: self.values.HandlePipeRequest(line, connection) line = connection.readline() continue if not connection.recvdata(): self.RemoveSocket(connection) continue while True: line = connection.readline() if not line: break try: self.values.HandleRequest(line, connection) except Exception as e: connection.write('error=invalid request: ' + line) try: print('invalid request from connection', e, line) except Exception as e2: print('invalid request has malformed string', e, e2) if not self.multiprocessing: # these pipes are not pollable as they are implemented as a simple buffer for pipe in self.pipes: while True: line = pipe.readline() if not line: break self.values.HandlePipeRequest(line, pipe) # send periodic watches self.values.send_watches() # send watches for connection in self.sockets + self.pipes: if connection.cwatches: connection.write('watch=' + pyjson.dumps(connection.cwatches) + '\n') connection.cwatches = {} # flush all sockets for socket in self.sockets: socket.flush() while True: for socket in self.sockets: if not socket.socket: print('server socket closed from flush!!') self.RemoveSocket(socket) break else: break for pipe in self.pipes: pipe.flush()
class SignalKClient(object): def __init__(self, f_on_connected, host=False, port=False, autoreconnect=False, have_watches=False): self.autoreconnect = autoreconnect config = {} configfilepath = os.getenv('HOME') + '/.pypilot/' if not os.path.exists(configfilepath): os.makedirs(configfilepath) if not os.path.isdir(configfilepath): raise configfilepath + 'should be a directory' self.configfilename = configfilepath + 'signalk.conf' self.write_config = False try: file = open(self.configfilename) config = kjson.loads(file.readline()) file.close() except Exception as e: print 'failed to read config file:', self.configfilename, e config = {} if not 'host' in config: config['host'] = '127.0.0.1' if not host: host = config['host'] if config['host'] != host: self.write_config = config self.write_config['host'] = host if not host: host = 'pypilot' print 'host not specified using host', host if '/dev' in host: # serial port device, baud = host, port if not baud or baud == 21311: baud = 9600 connection = serial.Serial(device, baud) cmd = 'stty -F ' + device + ' icanon iexten' print 'running', cmd os.system(cmd) else: if not port: if ':' in host: i = host.index(':') host = host[:i] port = host[i + 1:] else: port = DEFAULT_PORT try: connection = socket.create_connection((host, port), 1) except: print 'connect failed to %s:%d' % (host, port) raise self.host_port = host, port self.f_on_connected = f_on_connected self.have_watches = have_watches self.onconnected(connection) def onconnected(self, connection): if self.write_config: try: file = open(self.configfilename, 'w') file.write(kjson.dumps(self.write_config) + '\n') file.close() self.write_config = False except IOError: print 'failed to write config file:', self.configfilename except Exception as e: print 'Exception writing config file:', self.configfilename, e self.socket = LineBufferedNonBlockingSocket(connection) self.values = [] self.msg_queue = [] self.poller = select.poll() if self.socket: fd = self.socket.socket.fileno() else: fd = self.serial.fileno() self.poller.register(fd, select.POLLIN) self.f_on_connected(self) def poll(self, timeout=0): t0 = time.time() self.socket.flush() events = self.poller.poll(1000.0 * timeout) if events != []: event = events.pop() fd, flag = event if flag & (select.POLLERR | select.POLLNVAL): raise ConnectionLost if flag & select.POLLIN: if self.socket and not self.socket.recv(): raise ConnectionLost return True return False def send(self, request): self.socket.send(kjson.dumps(request) + '\n') def receive_line(self, timeout=0): line = self.socket.readline() if line: try: msg = kjson.loads(line.rstrip()) except: raise Exception('invalid message from server:', line) return msg if timeout < 0: return False t = time.time() try: if not self.poll(timeout): return False except ConnectionLost: self.disconnected() dt = time.time() - t return self.receive_line(timeout - dt) def disconnected(self): self.socket.socket.close() if not self.autoreconnect: raise ConnectionLost connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) while True: print 'Disconnected. Reconnecting in 3...' time.sleep(3) try: connection.connect(self.host_port) print 'Connected.' break except: continue self.onconnected(connection) def receive(self, timeout=0): ret = {} msg = self.receive_single(timeout) while msg: name, value = msg ret[name] = value msg = self.receive_single(-1) return ret def receive_single(self, timeout=0): if len(self.msg_queue) > 0: msg = self.msg_queue[0] self.msg_queue = self.msg_queue[1:] return msg line = self.receive_line(timeout) if line: self.msg_queue += self.flatten_line(line) return self.receive_single(-1) return False def flatten_line(self, line, name_prefix=''): msgs = [] for name in line: msg = line[name] if type(msg) == type({}): if 'value' in msg or 'type' in msg: msgs.append((name_prefix + name, msg)) else: msgs += self.flatten_line(msg, name_prefix + name + '/') return msgs def list_values(self, timeout=10): request = {'method': 'list'} self.send(request) t0 = t = time.time() while t - t0 <= timeout: t = time.time() try: return self.receive(timeout - t + t0) except Exception as e: print e return False def get(self, name): request = {'method': 'get', 'name': name} self.send(request) def set(self, name, value): # quote strings if type(value) == type('') or type(value) == type(u''): value = '"' + value + '"' elif type(value) == type(True): value = 'true' if value else 'false' request = '{"method": "set", "name": "' + name + '", "value": ' + str( value) + '}\n' self.socket.send(request) def watch(self, name, value=True): self.get(name) request = {'method': 'watch', 'name': name, 'value': value} self.send(request) def print_values(self, timeout, info=False): t0 = time.time() if not self.values: self.values = self.list_values(timeout) if not self.values: return False names = sorted(self.values) count = 0 results = {} while count < len(self.values): if names: self.get(names.pop()) else: time.sleep(.1) if time.time() - t0 >= timeout: return False while True: msg = self.receive_single() if not msg: break name, value = msg if name in results: break count += 1 results[name] = value for name in sorted(results): if info: print name, self.values[name], results[name] else: maxlen = 80 result = str(results[name]['value']) if len(name) + len(result) + 3 > maxlen: result = result[:80 - len(name) - 7] + ' ...' print name, '=', result return True
class pypilotClient(object): def __init__(self, host=False): if sys.version_info[0] < 3: import failedimports self.values = ClientValues(self) self.watches = {} self.wwatches = {} self.received = [] self.last_values_list = False if False: self.server = host host='127.0.0.1' if host and type(host) != type(''): # host is the server object for direct pipe connection self.server = host self.connection = host.pipe() self.poller = select.poll() fd = self.connection.fileno() if fd: self.poller.register(fd, select.POLLIN) self.values.onconnected() self.timeout_time = False # no timeout for pipe connection return self.timeout_time = time.monotonic() config = {} try: configfilepath = os.getenv('HOME') + '/.pypilot/' if not os.path.exists(configfilepath): os.makedirs(configfilepath) if not os.path.isdir(configfilepath): raise Exception(configfilepath + 'should be a directory') except Exception as e: print('os not supported') configfilepath = '/.pypilot/' self.configfilename = configfilepath + 'pypilot_client.conf' try: file = open(self.configfilename) config = pyjson.loads(file.readline()) file.close() except Exception as e: print(_('failed to read config file:'), self.configfilename, e) config = {} if host: if ':' in host: i = host.index(':') config['host'] = host[:i] config['port'] = host[i+1:] else: config['host'] = host if not 'host' in config: config['host'] = '127.0.0.1' if not 'port' in config: config['port'] = DEFAULT_PORT self.config = config self.connection = False # connect later self.connection_in_progress = False self.can_probe = True self.probed = False def onconnected(self): #print('connected to pypilot server', time.time()) self.last_values_list = False # write config if connection succeeds try: file = open(self.configfilename, 'w') file.write(pyjson.dumps(self.config) + '\n') file.close() self.write_config = False except IOError: print(_('failed to write config file:'), self.configfilename) except Exception as e: print(_('Exception writing config file:'), self.configfilename, e) self.connection = LineBufferedNonBlockingSocket(self.connection_in_progress, self.config['host']) self.connection_in_progress = False self.poller = select.poll() self.poller.register(self.connection.socket, select.POLLIN) self.wwatches = {} for name, value in self.watches.items(): self.wwatches[name] = value # resend watches self.values.onconnected() def probe(self): if not self.can_probe: return # do not search if host is specified by commandline, or again try: from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf except Exception as e: print(_('failed to') + ' import zeroconf, ' + _('autodetecting pypilot server not possible')) print(_('try') + ' pip3 install zeroconf' + _('or') + ' apt install python3-zeroconf') class Listener: def __init__(self, client): self.client = client def remove_service(self, zeroconf, type, name): pass def add_service(self, zeroconf, type, name): #print('service', name) self.name_type = name, type info = zeroconf.get_service_info(type, name) #print('info', info, info.parsed_addresses()[0]) if not info: return try: #for name, value in info.properties.items(): config = self.client.config #print('info', info.addresses) config['host'] = socket.inet_ntoa(info.addresses[0]) config['port'] = info.port print('found pypilot', config['host'], config['port']) self.client.probed = True zeroconf.close() except Exception as e: print('zeroconf service exception', e) self.can_probe = False zeroconf = Zeroconf() listener = Listener(self) browser = ServiceBrowser(zeroconf, "_pypilot._tcp.local.", listener) def poll(self, timeout=0): if not self.connection: if self.connection_in_progress: events = self.poller_in_progress.poll(0) if events: fd, flag = events.pop() if not (flag & select.POLLOUT): # hung hup self.connection_in_progress.close() self.connection_in_progress = False self.probe() return self.onconnected() return else: if not self.connect(False): time.sleep(timeout) return # inform server of any watches we have changed if self.wwatches: self.connection.write('watch=' + pyjson.dumps(self.wwatches) + '\n') #print('watch', watches, self.wwatches, self.watches) self.wwatches = {} # send any delayed watched values self.values.send_watches() if self.connection.fileno(): # flush output self.connection.flush() try: events = self.poller.poll(int(1000 * timeout)) except Exception as e: print('exception polling', e, os.getpid()) self.disconnect() return if not events: # 3 seconds without data in either direction, send linefeed # if the connection is lost, sending some data is needed # useful to cause the connection to reset if self.timeout_time and time.monotonic() - self.timeout_time > 3: self.update_timeout() self.send('\n') return # no data ready self.update_timeout() fd, flag = events.pop() if not (flag & select.POLLIN) or (self.connection and not self.connection.recvdata()): # other flags indicate disconnect self.disconnect() # recv returns 0 means connection closed return # read incoming data line by line while True: line = self.connection.readline() if not line: return #print('line', line, time.monotonic()) try: name, data = line.rstrip().split('=', 1) if name == 'error': print('server error:', data) continue value = pyjson.loads(data) except ValueError as e: print('client value error:', line, e) #raise Exception continue except Exception as e: print(_('invalid message from server:'), line, e) raise Exception() if name in self.values.values: # did this client register this value self.values.values[name].set(value) else: self.received.append((name, value)) # remote value # polls at least as long as timeout def disconnect(self): if self.connection: self.connection.close() self.connection = False def probewait(self, timeout): t0 = time.monotonic() while time.monotonic() - t0 < timeout: if self.probed: return True time.sleep(.1) return False def connect(self, verbose=True): if self.connection: print(_('warning, pypilot client aleady has connection')) try: host_port = self.config['host'], self.config['port'] self.connection_in_progress = False self.poller_in_progress = select.poll() self.connection_in_progress = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.connection_in_progress.settimeout(1) # set to 0 ? self.connection_in_progress.connect(host_port) except OSError as e: import errno if e.args[0] is errno.EINPROGRESS: self.poller_in_progress.register(self.connection_in_progress.fileno(), select.POLLOUT) return True self.connection_in_progress = False if e.args[0] == 111: # refused pass else: print(_('connect failed to') + (' %s:%d' % host_port), e) self.probe() #time.sleep(.25) return False #except Exception as e: # if verbose: # print('connect failed to %s:%d' % host_port, e) self.onconnected() return True def receive_single(self): if self.received: ret = self.received[0] self.received = self.received[1:] return ret return False def receive(self, timeout=0): self.poll(timeout) ret = {} for msg in self.received: name, value = msg ret[name] = value self.received = [] return ret def update_timeout(self): if self.timeout_time: self.timeout_time = time.monotonic() def send(self, msg): if self.connection: self.update_timeout() self.connection.write(msg) def set(self, name, value): # quote strings if type(value) == type('') or type(value) == type(u''): value = '"' + value + '"' elif type(value) == type(True): value = 'true' if value else 'false' self.send(name + '=' + str(value) + '\n') def watch(self, name, value=True): if name in self.watches: # already watching if value is False: del self.watches[name] self.wwatches[name] = value return elif self.watches[name] is value: return # same watch ignore elif value is False: return # already not watching self.watches[name] = value self.wwatches[name] = value def clear_watches(self): for name in self.watches: self.wwatches[name] = False self.watches = {} def register(self, value): self.values.register(value) value.client = self return value def get_values(self): if self.values.value: return self.values.value return {} def list_values(self, timeout=0): self.watch('values') t0, dt, ret = time.monotonic(), timeout, self.values.value while not ret and dt >= 0: self.poll(dt) ret = self.values.value dt = timeout - (time.monotonic()-t0) if self.last_values_list == ret: return False self.last_values_list = ret return ret def info(self, name): return self.values.value[name]
class gpsProcess(multiprocessing.Process): def __init__(self): # split pipe ends self.pipe, pipe = NonBlockingPipe('gps_pipe', True) super(gpsProcess, self).__init__(target=self.gps_process, args=(pipe,), daemon=True) def connect(self): time.sleep(2) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('127.0.0.1', 2947)) self.poller.register(sock, select.POLLIN) sock.settimeout(0) sock.send('?WATCH={"enable":true,"json":true};'.encode()) self.gpsd_socket = LineBufferedNonBlockingSocket(sock, 'gpsd') self.gpsconnecttime = time.monotonic() self.devices = [] print('gpsd connected') #except socket.error: except ConnectionRefusedError: print('gpsd failed to connect') self.gpsd_socket = False time.sleep(30) except Exception as e: self.gpsd_socket = False print('exception connecting to gps', e) time.sleep(60) def disconnect(self): print('gpsd disconnected') self.poller.unregister(self.gpsd_socket.socket) self.gpsd_socket.close() self.gpsd_socket = False self.devices = [] def read_pipe(self, pipe): while True: device = pipe.recv() if not device: break if self.gpsd_socket and not self.devices: # only probe if there are no gpsd devices print('gpsd PROBING...', device) if not os.system('timeout -s KILL -t 30 gpsctl -f ' + device + ' 2> /dev/null'): print('gpsd PROBE success', device) # probe was success os.environ['GPSD_SOCKET'] = '/tmp/gpsd.sock' os.environ['GPSD_OPTIONS'] = '-N -G -F /tmp/gpsd.sock' # should not run gpsd.. realpath = os.path.realpath(device) os.system('gpsdctl add ' + realpath) print('gpsd probe success: ' + device) self.devices = [device] else: print('gpsd probe failed') # always reply with devices when asked to probe print('GPSD send devices', self.devices) pipe.send({'devices': self.devices}) def parse_gpsd(self, msg, pipe): if not 'class' in msg: return False# unrecognized ret = False cls = msg['class'] if cls == 'DEVICES': self.devices = [] for dev in msg['devices']: self.devices.append(dev['path']) ret = True elif cls == 'DEVICE': device = msg['path'] if msg['activated']: if not device in self.devices: self.devices.append(device) ret = True else: print('gpsd deactivated', device, self.devices) if device in self.devices: self.devices.remove(device) ret = True elif cls == 'TPV': if msg['mode'] == 3: fix = {'speed': 0} for key in ['track', 'speed', 'lat', 'lon', 'device']: if key in msg: fix[key] = msg[key] fix['speed'] *= 1.944 # knots device = msg['device'] if self.baud_boot_device_hint != device: self.write_baud_boot_hint(device) if not device in self.devices: self.devices.append(device) ret = True pipe.send(fix, False) return ret def write_baud_boot_hint(self, device): self.baud_boot_device_hint = device try: stty=os.popen('sudo stty -F ' + device) line = stty.readline() stty.close() speed = line.index('speed') baud = line.index('baud') bps = int(line[speed+6:baud-1]) f = open(os.getenv('HOME') + '/.pypilot/gpsd_baud_hint', 'w') f.write(str(bps)) f.close() except Exception as e: print('gpsd failed to determine serial baud rate of device') def gps_process(self, pipe): print('gps process', os.getpid()) self.gpsd_socket = False self.poller = select.poll() self.baud_boot_device_hint = '' while True: self.read_pipe(pipe) if not self.gpsd_socket: self.connect() continue events = self.poller.poll(1000) #print('gpsd poll', events) if not events: if self.gpsconnecttime and time.monotonic() - self.gpsconnecttime > 10: print('gpsd timeout from lack of data') self.disconnect(); continue self.gpsconnecttime = False fd, flag = events.pop() if flag & select.POLLIN and self.gpsd_socket.recvdata(): while True: line = self.gpsd_socket.readline() if not line: break try: if self.parse_gpsd(gps_json_loads(line), pipe): pipe.send({'devices': self.devices}) except Exception as e: print('gpsd received invalid message', line, e) else: # gpsd connection lost self.disconnect() pipe.send({'devices': self.devices})