示例#1
0
    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()
示例#2
0
文件: gpsd.py 项目: vhn0912/PyPilot
 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)
示例#3
0
    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)
示例#4
0
    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()
示例#5
0
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]
示例#6
0
    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()
示例#7
0
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
示例#8
0
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]
示例#9
0
文件: gpsd.py 项目: vhn0912/PyPilot
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})