Beispiel #1
0
class RTL433ProcessProtocol(ProcessProtocol):
    def __init__(self, target):
        self.__target = target
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = '\n'
        self.__line_receiver.lineReceived = self.__lineReceived
    
    def outReceived(self, data):
        """Implements ProcessProtocol."""
        # split lines
        self.__line_receiver.dataReceived(data)
        
    def errReceived(self, data):
        """Implements ProcessProtocol."""
        # we should inherit stderr, not pipe it
        raise Exception('shouldn\'t happen')
    
    def __lineReceived(self, line):
        # rtl_433's JSON encoder is not perfect (e.g. it will emit unescaped newlines), so protect against parse failures
        try:
            message = json.loads(line)
        except ValueError:
            log.msg('bad JSON from rtl_433: %s' % line)
            return
        log.msg('rtl_433 message: %r' % (message,))
        # rtl_433 provides a time field, but when in file-input mode it assumes the input is not real-time and generates start-of-file-relative timestamps, so we can't use them.
        wrapper = RTL433MessageWrapper(message, time.time())
        self.__target(wrapper)
Beispiel #2
0
class APRSProcessProtocol(ProcessProtocol):
    def __init__(self, target):
        self.__target = target
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = '\n'
        self.__line_receiver.lineReceived = self.__lineReceived
        self.__last_line = None

    def outReceived(self, data):
        # split lines
        self.__line_receiver.dataReceived(data)

    def errReceived(self, data):
        # we should inherit stderr, not pipe it
        raise Exception('shouldn\'t happen')

    def __lineReceived(self, line):
        if line == '':  # observed glitch in output
            pass
        elif line.startswith('Enabled demodulators:'):
            pass
        elif line.startswith(
                '$ULTW'
        ) and self.__last_line is not None:  # observed glitch in output; need to glue to previous line, I think?
            ll = self.__last_line
            self.__last_line = None
            self.__target(ll + line)
        elif line.startswith('APRS: '):
            line = line[len('APRS: '):]
            self.__last_line = line
            self.__target(line)
        else:
            # TODO: Log these properly
            print 'Not APRS line: %r' % line
Beispiel #3
0
class APRSProcessProtocol(ProcessProtocol):
    def __init__(self, target):
        self.__target = target
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = '\n'
        self.__line_receiver.lineReceived = self.__lineReceived
        self.__last_line = None
    
    def outReceived(self, data):
        # split lines
        self.__line_receiver.dataReceived(data)
        
    def errReceived(self, data):
        # we should inherit stderr, not pipe it
        raise Exception('shouldn\'t happen')
    
    def __lineReceived(self, line):
        if line == '':  # observed glitch in output
            pass
        elif line.startswith('Enabled demodulators:'):
            pass
        elif line.startswith('$ULTW') and self.__last_line is not None:  # observed glitch in output; need to glue to previous line, I think?
            ll = self.__last_line
            self.__last_line = None
            self.__target(ll + line)
        elif line.startswith('APRS: '):
            line = line[len('APRS: '):]
            self.__last_line = line
            self.__target(line)
        else:
            # TODO: Log these properly
            print 'Not APRS line: %r' % line
Beispiel #4
0
class RTL433ProcessProtocol(ProcessProtocol):
    def __init__(self, target):
        self.__target = target
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = '\n'
        self.__line_receiver.lineReceived = self.__lineReceived

    def outReceived(self, data):
        """Implements ProcessProtocol."""
        # split lines
        self.__line_receiver.dataReceived(data)

    def errReceived(self, data):
        """Implements ProcessProtocol."""
        # we should inherit stderr, not pipe it
        raise Exception('shouldn\'t happen')

    def __lineReceived(self, line):
        # rtl_433's JSON encoder is not perfect (e.g. it will emit unescaped newlines), so protect against parse failures
        try:
            message = json.loads(line)
        except ValueError:
            log.msg('bad JSON from rtl_433: %s' % line)
            return
        log.msg('rtl_433 message: %r' % (message, ))
        # rtl_433 provides a time field, but when in file-input mode it assumes the input is not real-time and generates start-of-file-relative timestamps, so we can't use them.
        wrapper = RTL433MessageWrapper(message, time.time())
        self.__target(wrapper)
Beispiel #5
0
    def dataReceived(self, *args, **kwargs):
        # receives the data then checks if the request is complete.
        # if it is, it calls full_Request_received
        LineReceiver.dataReceived(self, *args, **kwargs)

        if self._request_obj.complete:
            self.full_request_received()
Beispiel #6
0
    def dataReceived(self, *args, **kwargs):
        # receives the data then checks if the request is complete.
        # if it is, it calls full_Request_received
        LineReceiver.dataReceived(self, *args, **kwargs)

        if self._request_obj.complete:
            self.full_request_received()
Beispiel #7
0
 def dataReceived(self, data):
     if self.factory.stream_response and self.stream_response:
         self.factory.return_transport.write(data)
     LineReceiver.dataReceived(self, data)
     if not self.completed:
         if self._response_obj.complete:
             self.completed = True
             self.handle_response_end()
Beispiel #8
0
 def dataReceived(self, data):
     if self.factory.stream_response:
         self.factory.return_transport.write(data)
     LineReceiver.dataReceived(self, data)
     if not self.completed:
         if self._response_obj.complete:
             self.completed = True
             self.handle_response_end()
Beispiel #9
0
class PostgresMonitor(ProcessProtocol):
    """
    A monitoring protocol which watches the postgres subprocess.
    """
    log = Logger()

    def __init__(self, svc=None):
        self.lineReceiver = LineReceiver()
        self.lineReceiver.delimiter = '\n'
        self.lineReceiver.lineReceived = self.lineReceived
        self.svc = svc
        self.isReady = False
        self.completionDeferred = Deferred()


    def lineReceived(self, line):
        if self.svc is None:
            return
        if not self.isReady:
            if _MAGIC_READY_COOKIE in line:
                self.svc.ready()

    disconnecting = False


    def connectionMade(self):
        self.lineReceiver.makeConnection(self)


    def outReceived(self, out):
        for line in out.split("\n"):
            if line:
                self.log.info("{message}", message=line)
        # self.lineReceiver.dataReceived(out)


    def errReceived(self, err):
        for line in err.split("\n"):
            if line:
                self.log.error("{message}", message=line)
        self.lineReceiver.dataReceived(err)


    def processEnded(self, reason):
        self.log.info(
            "pg_ctl process ended with status={status}",
            status=reason.value.status
        )
        # If pg_ctl exited with zero, we were successful in starting postgres
        # If pg_ctl exited with nonzero, we need to give up.
        self.lineReceiver.connectionLost(reason)

        if reason.value.status == 0:
            self.completionDeferred.callback(None)
        else:
            self.log.error("Could not start postgres; see postgres.log")
            self.completionDeferred.errback(reason)
Beispiel #10
0
    def dataReceived(self, *args, **kwargs):
        # receives the data then checks if the request is complete.
        # if it is, it calls full_Request_received
        LineReceiver.dataReceived(self, *args, **kwargs)

        if self._request_obj.complete:
            try:
                self.full_request_received()
            except PappyException as e:
                print str(e)
Beispiel #11
0
    def dataReceived(self, *args, **kwargs):
        # receives the data then checks if the request is complete.
        # if it is, it calls full_Request_received
        LineReceiver.dataReceived(self, *args, **kwargs)

        if self._request_obj.complete:
            try:
                self.full_request_received()
            except PappyException as e:
                print str(e)
Beispiel #12
0
class _PostgresMonitor(ProcessProtocol):
    """
    A monitoring protocol which watches the postgres subprocess.
    """

    def __init__(self, svc=None):
        self.lineReceiver = LineReceiver()
        self.lineReceiver.delimiter = '\n'
        self.lineReceiver.lineReceived = self.lineReceived
        self.svc = svc
        self.isReady = False
        self.completionDeferred = Deferred()


    def lineReceived(self, line):
        if self.svc is None:
            return
        if not self.isReady:
            if _MAGIC_READY_COOKIE in line:
                self.svc.ready()

    disconnecting = False


    def connectionMade(self):
        self.lineReceiver.makeConnection(self)


    def outReceived(self, out):
        log.warn("received postgres stdout {out!r}", out=out)
        # self.lineReceiver.dataReceived(out)


    def errReceived(self, err):
        log.warn("received postgres stderr {err}", err=err)
        self.lineReceiver.dataReceived(err)


    def processEnded(self, reason):
        log.warn(
            "postgres process ended with status {status}",
            status=reason.value.status
        )
        # If pg_ctl exited with zero, we were successful in starting postgres
        # If pg_ctl exited with nonzero, we need to give up.
        self.lineReceiver.connectionLost(reason)

        if reason.value.status == 0:
            self.completionDeferred.callback(None)
        else:
            log.warn("Could not start postgres; see postgres.log")
            self.completionDeferred.errback(reason)
Beispiel #13
0
class CommandReceiver(channel.ChannelReceiver):

    def __init__(self):
        self.lineReceiver = LineReceiver()
        self.lineReceiver.lineReceived = self.lineReceived

    def lineReceived(self, line):
        cmd, data = line.split(':', 1)
        self.commandReceived(cmd.strip(), data.strip())

    def commandReceived(self, cmd, data):
        raise NotImplementedError

    def sendCommand(self, cmd, data):
        return self.send(self.cmd_channel, '%s: %s\r\n' % (cmd, data))

    def channeReceived(self, channel, type, data):
        if channel == self.cmd_channel:
            self.lineReceiver.dataReceived(data)
class _PostgresMonitor(ProcessProtocol):
    """
    A monitoring protocol which watches the postgres subprocess.
    """

    def __init__(self, svc=None):
        self.lineReceiver = LineReceiver()
        self.lineReceiver.delimiter = '\n'
        self.lineReceiver.lineReceived = self.lineReceived
        self.svc = svc
        self.isReady = False
        self.completionDeferred = Deferred()


    def lineReceived(self, line):
        if self.svc is None:
            return
        if not self.isReady:
            if _MAGIC_READY_COOKIE in line:
                self.svc.ready()

    disconnecting = False


    def connectionMade(self):
        self.lineReceiver.makeConnection(self)


    def outReceived(self, out):
        log.msg("received postgres stdout %r" % (out,))
        # self.lineReceiver.dataReceived(out)


    def errReceived(self, err):
        log.msg("received postgres stderr %r" % (err,))
        self.lineReceiver.dataReceived(err)


    def processEnded(self, reason):
        log.msg("postgres process ended %r" % (reason,))
        result = (reason.value.status == 0)
        self.lineReceiver.connectionLost(reason)
        self.completionDeferred.callback(result)
Beispiel #15
0
class LineBuffer(object):
    """
    A line-buffering wrapper for L{GreenletTransport}s (or any other object
    with C{read} and C{write} methods). Call L{readLine} to get the next line,
    call L{writeLine} to write a line.
    """
    def __init__(self, transport, delimiter="\r\n"):
        """
        @param transport: The transport from which to read bytes and to which
            to write them!
        @type transport: L{GreenletTransport}
        @param delimiter: The line delimiter to split lines on.
        @type delimiter: C{str}
        """
        self.delimiter = delimiter
        self.transport = transport
        self.receiver = LineReceiver()
        self.receiver.delimiter = delimiter
        self.lines = []
        self.receiver.lineReceived = self.lines.append

    def writeLine(self, data):
        """
        Write some data to the transport followed by the delimiter.
        """
        self.transport.write(data + self.delimiter)

    def readLine(self):
        """
        Return a line of data from the transport.
        """
        while not self.lines:
            self.receiver.dataReceived(self.transport.read())
        return self.lines.pop(0)

    def __iter__(self):
        """
        Yield the result of L{readLine} forever.
        """
        while True:
            yield self.readLine()
Beispiel #16
0
class LineBuffer(object):
    """
    A line-buffering wrapper for L{GreenletTransport}s (or any other object
    with C{read} and C{write} methods). Call L{readLine} to get the next line,
    call L{writeLine} to write a line.
    """
    def __init__(self, transport, delimiter="\r\n"):
        """
        @param transport: The transport from which to read bytes and to which
            to write them!
        @type transport: L{GreenletTransport}
        @param delimiter: The line delimiter to split lines on.
        @type delimiter: C{str}
        """
        self.delimiter = delimiter
        self.transport = transport
        self.receiver = LineReceiver()
        self.receiver.delimiter = delimiter
        self.lines = []
        self.receiver.lineReceived = self.lines.append

    def writeLine(self, data):
        """
        Write some data to the transport followed by the delimiter.
        """
        self.transport.write(data + self.delimiter)

    def readLine(self):
        """
        Return a line of data from the transport.
        """
        while not self.lines:
            self.receiver.dataReceived(self.transport.read())
        return self.lines.pop(0)

    def __iter__(self):
        """
        Yield the result of L{readLine} forever.
        """
        while True:
            yield self.readLine()
Beispiel #17
0
class _ControllerProtocol(Protocol):
    def __init__(self):
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = b';'
        self.__line_receiver.lineReceived = self.__lineReceived
    
    def connectionMade(self):
        """overrides Protocol"""
        # TODO: Report success
    
    def connectionLost(self, reason=None):
        """overrides Protocol"""
        # TODO: Report loss to user
    
    def dataReceived(self, data):
        """overrides Protocol"""
        self.__line_receiver.dataReceived(data)
    
    def __lineReceived(self, line):
        print line
    
    def send(self, cmd):
        self.transport.write(cmd)
Beispiel #18
0
class _ControllerProtocol(Protocol):
    def __init__(self):
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = ';'
        self.__line_receiver.lineReceived = self.__lineReceived

    def connectionMade(self):
        """overrides Protocol"""
        # TODO: Report success

    def connectionLost(self, reason=None):
        """overrides Protocol"""
        # TODO: Report loss to user

    def dataReceived(self, data):
        """overrides Protocol"""
        self.__line_receiver.dataReceived(data)

    def __lineReceived(self, line):
        print line

    def send(self, cmd):
        self.transport.write(cmd)
Beispiel #19
0
 def dataReceived(self, data):
     print "[raw data] {}".format(data)
     LineReceiver.dataReceived(self, data)
Beispiel #20
0
	def dataReceived(self, data):
		self.resetTimeout()
		LineReceiver.dataReceived(self, data)
Beispiel #21
0
class _HamlibClientProtocol(Protocol):
    def __init__(self, server_name, connected_deferred, log):
        self.__server_name = server_name
        self.__connected_deferred = connected_deferred
        self.__log = log

        self.__proxy_obj = None
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = b'\n'
        self.__line_receiver.lineReceived = self.__lineReceived
        self.__waiting_for_responses = []
        self.__receive_cmd = None
        self.__receive_arg = None

    def connectionMade(self):
        self.__connected_deferred.callback(self)

    def connectionLost(self, reason):
        # pylint: disable=signature-differs
        if self.__proxy_obj is not None:
            self.__proxy_obj._clientConnectionLost(reason)

    def dataReceived(self, data):
        self.__line_receiver.dataReceived(data)

    def __lineReceived(self, line):
        line = six.text_type(line,
                             'us-ascii')  # TODO verify best choice of encoding
        if self.__receive_cmd is None:
            match = re.match(r'^(\w+):\s*(.*)$', line)
            if match is not None:
                # command response starting line
                self.__receive_cmd = match.group(1)
                self.__receive_arg = match.group(2)
                return
            self.__log.error(
                '%s client: Unrecognized line (no command active): %r' %
                (self.__server_name, line))  # TODO use logger formatting
        else:
            match = re.match(r'^RPRT (-?\d+)$', line)
            if match is not None:
                # command response ending line
                return_code = int(match.group(1))

                waiting = self.__waiting_for_responses
                i = 0
                for i, (wait_cmd, wait_deferred) in enumerate(waiting):
                    if self.__receive_cmd != wait_cmd:
                        self.__log.error(
                            "%s client: Didn't get a response for command %r before receiving one for command %r"
                            %
                            (self.__server_name, wait_cmd,
                             self.__receive_cmd))  # TODO use logger formatting
                    else:
                        # TODO: Consider 'parsing' return code more here.
                        if return_code != 0:
                            self.__proxy_obj._clientError(
                                self.__receive_cmd, return_code)
                        wait_deferred.callback(return_code)
                        break
                self.__waiting_for_responses = waiting[i + 1:]

                self.__receive_cmd = None
                self.__receive_arg = None
                return
            if self.__receive_cmd == 'get_level':
                # Should be a level value
                match = re.match(r'^-?\d+\.?\d*$', line)
                if match:
                    self.__proxy_obj._clientReceivedLevel(
                        self.__receive_arg, line)
                    return
            match = re.match(r'^([\w ,/-]+):\s*(.*)$', line)
            if match is not None:
                # Command response
                if self.__proxy_obj is not None:
                    self.__proxy_obj._clientReceived(self.__receive_cmd,
                                                     match.group(1),
                                                     match.group(2))
                    return
            match = re.match(r'^\t', line)
            if match is not None and self.__receive_cmd == 'dump_caps':
                # Sub-info from dump_caps, not currently used
                return
            match = re.match(r'^Warning--', line)
            if match is not None:
                # Warning from dump_caps, not currently used
                return
            match = re.match(r'^$', line)
            if match is not None:
                return
            self.__log.error('%s client: Unrecognized line during %s: %r' %
                             (self.__server_name, self.__receive_cmd,
                              line))  # TODO use logger formatting

    def _set_proxy(self, proxy):
        self.__proxy_obj = proxy

    def rc_send(self, cmd, argstr=''):
        if not re.match(
                r'^\w+$', cmd
        ):  # no spaces (stuffing args in), no newlines (breaking the command)
            raise ValueError('Syntactically invalid command name %r' % (cmd, ))
        if not re.match(r'^[^\r\n]*$', argstr):  # no newlines
            raise ValueError('Syntactically invalid arguments string %r' %
                             (cmd, ))
        self.transport.write(
            ('+\\' + cmd + ' ' + argstr + '\n').encode('us-ascii'))
        d = defer.Deferred()
        self.__waiting_for_responses.append((cmd, d))
        return d
Beispiel #22
0
class _HamlibClientProtocol(Protocol):
    def __init__(self, server_name, connected_deferred):
        self.__proxy_obj = None
        self.__server_name = server_name
        self.__connected_deferred = connected_deferred
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = '\n'
        self.__line_receiver.lineReceived = self.__lineReceived
        self.__waiting_for_responses = []
        self.__receive_cmd = None
        self.__receive_arg = None
    
    def connectionMade(self):
        self.__connected_deferred.callback(self)
    
    def connectionLost(self, reason):
        # pylint: disable=signature-differs
        if self.__proxy_obj is not None:
            self.__proxy_obj._clientConnectionLost(reason)
    
    def dataReceived(self, data):
        self.__line_receiver.dataReceived(data)
    
    def __lineReceived(self, line):
        if self.__receive_cmd is None:
            match = re.match(r'^(\w+):\s*(.*)$', line)
            if match is not None:
                # command response starting line
                self.__receive_cmd = match.group(1)
                self.__receive_arg = match.group(2)
                return
            log.err('%s client: Unrecognized line (no command active): %r' % (self.__server_name, line))
        else:
            match = re.match(r'^RPRT (-?\d+)$', line)
            if match is not None:
                # command response ending line
                return_code = int(match.group(1))
                
                waiting = self.__waiting_for_responses
                i = 0
                for i, (wait_cmd, wait_deferred) in enumerate(waiting):
                    if self.__receive_cmd != wait_cmd:
                        log.err("%s client: Didn't get a response for command %r before receiving one for command %r" % (self.__server_name, wait_cmd, self.__receive_cmd))
                    else:
                        # TODO: Consider 'parsing' return code more here.
                        if return_code != 0:
                            self.__proxy_obj._clientError(self.__receive_cmd, return_code)
                        wait_deferred.callback(return_code)
                        break
                self.__waiting_for_responses = waiting[i + 1:]
                
                self.__receive_cmd = None
                self.__receive_arg = None
                return
            if self.__receive_cmd == 'get_level':
                # Should be a level value
                match = re.match(r'^-?\d+\.?\d*$', line)
                if match:
                    self.__proxy_obj._clientReceivedLevel(self.__receive_arg, line)
                    return
            match = re.match(r'^([\w ,/-]+):\s*(.*)$', line)
            if match is not None:
                # Command response
                if self.__proxy_obj is not None:
                    self.__proxy_obj._clientReceived(self.__receive_cmd, match.group(1), match.group(2))
                    return
            match = re.match(r'^\t', line)
            if match is not None and self.__receive_cmd == 'dump_caps':
                # Sub-info from dump_caps, not currently used
                return
            match = re.match(r'^Warning--', line)
            if match is not None:
                # Warning from dump_caps, not currently used
                return
            match = re.match(r'^$', line)
            if match is not None:
                return
            log.err('%s client: Unrecognized line during %s: %r' % (self.__server_name, self.__receive_cmd, line))
    
    def _set_proxy(self, proxy):
        self.__proxy_obj = proxy
    
    def rc_send(self, cmd, argstr=''):
        if not re.match(r'^\w+$', cmd):  # no spaces (stuffing args in), no newlines (breaking the command)
            raise ValueError('Syntactically invalid command name %r' % (cmd,))
        if not re.match(r'^[^\r\n]*$', argstr):  # no newlines
            raise ValueError('Syntactically invalid arguments string %r' % (cmd,))
        self.transport.write('+\\' + cmd + ' ' + argstr + '\n')
        d = defer.Deferred()
        self.__waiting_for_responses.append((cmd, d))
        return d
Beispiel #23
0
 def dataReceived(self, data):
     LineReceiver.dataReceived(self, data)
     if data == "\x04":
         self.transport.loseConnection()
Beispiel #24
0
 def dataReceived(self, data):
     if data == "\r":
         data = "\r\n"
     return LineReceiver.dataReceived(self, data)
Beispiel #25
0
	def dataReceived(self, data):
		LineReceiver.dataReceived(self, data)
Beispiel #26
0
class _ElecraftClientProtocol(Protocol):
    def __init__(self, reactor):
        self.__reactor = reactor
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = b';'
        self.__line_receiver.lineReceived = self.__lineReceived
        self.__communication_error = u'not_responding'
        
        self.__explicit_waits = defaultdict(list)
        
        # set up dummy initial state
        self.__scheduled_poll = reactor.callLater(0, lambda: None)
        self.__scheduled_poll.cancel()
        
        # Set up proxy.
        # Do this last because the proxy fetches metadata from us so we should be otherwise fully initialized.
        self.__proxy_obj = _ElecraftRadio(self)
    
    def connectionMade(self):
        """overrides Protocol"""
        self.__reinitialize()
    
    def connectionLost(self, reason):
        # pylint: disable=signature-differs
        """overrides Protocol"""
        if self.__scheduled_poll.active():
            self.__scheduled_poll.cancel()
        self.__communication_error = u'serial_gone'
    
    def get_communication_error(self):
        return self.__communication_error
    
    def dataReceived(self, data):
        """overrides Protocol"""
        self.__line_receiver.dataReceived(data)
    
    def send_command(self, cmd_text):
        """Send a raw command.
        
        The text must include its trailing semicolon.
        
        If wait=True, return a Deferred.
        """
        if isinstance(cmd_text, unicode):
            cmd_text = cmd_text.encode('us-ascii')  # TODO: correct choice of encoding
        assert cmd_text == b'' or cmd_text.endswith(b';')
        self.transport.write(cmd_text)
    
    def get(self, name):
        """TODO explain
        
        Note that this may wait too little time, if the same command is already in flight.
        """
        d = defer.Deferred()
        self.__explicit_waits[name].append(d)
        self.send_command(name + ';')
        return d
    
    def __reinitialize(self):
        # TODO: Use ID, K3, and OM commands to confirm identity and customize
        self.transport.write(
            b'AI2;'  # Auto-Info Mode 2; notification of any change (delayed)
            b'K31;')  # enable extended response, important for FW command
        self.request_all()  # also triggers polling cycle
    
    def __schedule_timeout(self):
        if self.__scheduled_poll.active():
            self.__scheduled_poll.cancel()
        self.__scheduled_poll = self.__reactor.callLater(1, self.__poll_doubtful)
    
    def __schedule_got_response(self):
        if self.__scheduled_poll.active():
            self.__scheduled_poll.cancel()
        self.__scheduled_poll = self.__reactor.callLater(0.04, self.__poll_fast_reactive)
    
    def request_all(self):
        self.transport.write(
            b'IF;'
            b'AG;AG$;AN;AP;BN;BN$;BW;BW$;CP;CW;DV;ES;FA;FB;FI;FR;FT;GT;IS;KS;'
            b'LK;LK$;LN;MC;MD;MD$;MG;ML;NB;NB$;PA;PA$;PC;RA;RA$;RG;RG$;SB;SQ;'
            b'SQ$;VX;XF;XF$;')
        # If we don't get a response, this fires
        self.__schedule_timeout()
    
    def __poll_doubtful(self):
        """If this method is called then we didn't get a prompt response."""
        self.__communication_error = 'not_responding'
        self.transport.write(b'FA;')
        self.__schedule_timeout()
    
    def __poll_fast_reactive(self):
        """Normal polling activity."""
        # Get FA (VFO A frequency) so we respond fast.
        # Get BN (band) because if we find out we changed bands we need to update band-dependent things.
        # Get MD (mode) because on KX3, A/B button does not report changes
        self.transport.write(b'FA;BN;MD;MD$;')
        self.__schedule_timeout()
    
    def __lineReceived(self, line):
        line = line.lstrip('\x00')  # nulls are sometimes sent on power-on
        # log.msg('Elecraft client: received %r' % (line,))
        if '\x00' in line:
            # Bad data that may be received during radio power-on
            return
        elif line == '?':
            # busy indication; nothing to do about it as yet
            pass
        else:
            try:
                cmd = line[:2]
                sub = len(line) > 2 and line[2] == '$'
                cmd_sub = cmd + ('$' if sub else '')
                data = line[(3 if sub else 2):]
                
                handler = _st.dispatch(cmd)
                if handler is not None:
                    handler(data, sub, self._update)
                else:
                    log.msg('Elecraft client: unrecognized message %r in %r' % (cmd, line))
                
                if cmd_sub in self.__explicit_waits:
                    waits = self.__explicit_waits[cmd_sub]
                    del self.__explicit_waits[cmd_sub]
                    for d in waits:
                        self.__reactor.callLater(0, d.callback, data)
            except ValueError as e:  # bad digits or whatever
                log.err(e, 'Elecraft client: error while parsing message %r' % (line,))
                self.__communication_error = 'bad_data'
                return  # don't consider as OK, but don't reinit either
        
        if not self.__communication_error:
            # communication is still OK
            self.__schedule_got_response()
        else:
            self.__communication_error = None
            # If there was a communication error, we might be out of sync, so resync and also start up normal polling.
            self.__reinitialize()
    
    def _update(self, key, value, sub=False):
        """Handle a received value update."""
        # TODO less poking at internals, more explicit
        cell = self.__proxy_obj.state().get(key)
        if not cell:
            cell = (self.__proxy_obj.get_rx_sub() if sub else self.__proxy_obj.get_rx_main()).state().get(key)
        
        if cell:
            old_value = cell.get()
            cell.set_internal(value)
        else:
            # just don't crash
            log.msg('Elecraft client: missing cell for state %r' % (key,))
        
        if key == 'band' and value != old_value:
            # Band change! Check the things we don't get prompt or any notifications for.
            self.request_all()
    
    def _proxy(self):
        """for use by connect_to_rig"""
        return self.__proxy_obj
Beispiel #27
0
class _ElecraftClientProtocol(Protocol):
    __log = Logger()

    def __init__(self, reactor):
        self.__reactor = reactor
        self.__line_receiver = LineReceiver()
        self.__line_receiver.delimiter = b';'
        self.__line_receiver.lineReceived = self.__lineReceived
        self.__communication_error = u'not_responding'

        self.__explicit_waits = defaultdict(list)

        # set up dummy initial state
        self.__scheduled_poll = reactor.callLater(0, lambda: None)
        self.__scheduled_poll.cancel()

        # Set up proxy.
        # Do this last because the proxy fetches metadata from us so we should be otherwise fully initialized.
        self.__proxy_obj = _ElecraftRadio(self)

    def connectionMade(self):
        """overrides Protocol"""
        self.__reinitialize()

    def connectionLost(self, reason):
        # pylint: disable=signature-differs
        """overrides Protocol"""
        if self.__scheduled_poll.active():
            self.__scheduled_poll.cancel()
        self.__communication_error = u'serial_gone'

    def get_communication_error(self):
        return self.__communication_error

    def dataReceived(self, data):
        """overrides Protocol"""
        self.__line_receiver.dataReceived(data)

    def send_command(self, cmd_text):
        """Send a raw command.
        
        The text must include its trailing semicolon.
        
        If wait=True, return a Deferred.
        """
        if isinstance(cmd_text, six.text_type):
            cmd_text = cmd_text.encode(
                'us-ascii')  # TODO: correct choice of encoding
        assert isinstance(cmd_text, bytes)
        assert cmd_text == b'' or cmd_text.endswith(b';')
        self.transport.write(cmd_text)

    def get(self, name):
        """TODO explain
        
        Note that this may wait too little time, if the same command is already in flight.
        """
        d = defer.Deferred()
        self.__explicit_waits[name].append(d)
        self.send_command(name + ';')
        return d

    def __reinitialize(self):
        # TODO: Use ID, K3, and OM commands to confirm identity and customize
        self.transport.write(
            b'AI2;'  # Auto-Info Mode 2; notification of any change (delayed)
            b'K31;')  # enable extended response, important for FW command
        self.request_all()  # also triggers polling cycle

    def __schedule_timeout(self):
        if self.__scheduled_poll.active():
            self.__scheduled_poll.cancel()
        self.__scheduled_poll = self.__reactor.callLater(
            1, self.__poll_doubtful)

    def __schedule_got_response(self):
        if self.__scheduled_poll.active():
            self.__scheduled_poll.cancel()
        self.__scheduled_poll = self.__reactor.callLater(
            0.04, self.__poll_fast_reactive)

    def request_all(self):
        self.transport.write(
            b'IF;'
            b'AG;AG$;AN;AP;BN;BN$;BW;BW$;CP;CW;DV;ES;FA;FB;FI;FR;FT;GT;IS;KS;'
            b'LK;LK$;LN;MC;MD;MD$;MG;ML;NB;NB$;PA;PA$;PC;RA;RA$;RG;RG$;SB;SQ;'
            b'SQ$;VX;XF;XF$;')
        # If we don't get a response, this fires
        self.__schedule_timeout()

    def __poll_doubtful(self):
        """If this method is called then we didn't get a prompt response."""
        self.__communication_error = 'not_responding'
        self.transport.write(b'FA;')
        self.__schedule_timeout()

    def __poll_fast_reactive(self):
        """Normal polling activity."""
        # Get FA (VFO A frequency) so we respond fast.
        # Get BN (band) because if we find out we changed bands we need to update band-dependent things.
        # Get MD (mode) because on KX3, A/B button does not report changes
        self.transport.write(b'FA;BN;MD;MD$;')
        self.__schedule_timeout()

    def __lineReceived(self, line):
        line = line.lstrip(b'\x00')  # nulls are sometimes sent on power-on
        self.__log.debug('Elecraft client: received {line!r}', line=line)
        if b'\x00' in line:
            # Bad data that may be received during radio power-on
            return
        elif line == b'?':
            # busy indication; nothing to do about it as yet
            pass
        else:
            try:
                cmd = six.text_type(line[:2], 'ascii')
                sub = len(line) > 2 and line[2] == b'$'
                cmd_sub = cmd + ('$' if sub else '')
                data = line[(3 if sub else 2):]

                handler = _st.dispatch(cmd)
                if handler is not None:
                    handler(data, sub, self._update)
                else:
                    self.__log.warn(
                        'Elecraft client: unrecognized message {cmd!r} in {line!r}',
                        cmd=cmd,
                        line=line)

                if cmd_sub in self.__explicit_waits:
                    waits = self.__explicit_waits[cmd_sub]
                    del self.__explicit_waits[cmd_sub]
                    for d in waits:
                        self.__reactor.callLater(0, d.callback, data)
            except ValueError:  # bad digits or whatever
                self.__log.failure(
                    'Elecraft client: error while parsing message {line!r}',
                    line=line)
                self.__communication_error = 'bad_data'
                return  # don't consider as OK, but don't reinit either

        if not self.__communication_error:
            # communication is still OK
            self.__schedule_got_response()
        else:
            self.__communication_error = None
            # If there was a communication error, we might be out of sync, so resync and also start up normal polling.
            self.__reinitialize()

    def _update(self, key, value, sub=False):
        """Handle a received value update."""
        # TODO less poking at internals, more explicit
        cell = self.__proxy_obj.state().get(key)
        if not cell:
            cell = (self.__proxy_obj.get_rx_sub() if sub else
                    self.__proxy_obj.get_rx_main()).state().get(key)

        if cell:
            old_value = cell.get()
            cell.set_internal(value)
        else:
            # just don't crash
            self.__log.warn('Elecraft client: missing cell for state {key!r}',
                            key=key)

        if key == 'band' and value != old_value:
            # Band change! Check the things we don't get prompt or any notifications for.
            self.request_all()

    def _proxy(self):
        """for use by connect_to_rig"""
        return self.__proxy_obj
Beispiel #28
0
 def dataReceived(self, data):
     if data == "\r":
         data = "\r\n"
     return LineReceiver.dataReceived(self, data)
Beispiel #29
0
 def dataReceived(self, data):
     # translate '\r' into '\n'
     return LineReceiver.dataReceived(self, data.replace('\r', '\n'))
Beispiel #30
0
 def dataReceived(self, data):
     self.resetTimeout()
     LineReceiver.dataReceived(self, data)