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)
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
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
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)
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()
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()
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()
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()
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)
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)
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)
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)
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)
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()
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()
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)
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)
def dataReceived(self, data): print "[raw data] {}".format(data) LineReceiver.dataReceived(self, data)
def dataReceived(self, data): self.resetTimeout() LineReceiver.dataReceived(self, data)
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
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
def dataReceived(self, data): LineReceiver.dataReceived(self, data) if data == "\x04": self.transport.loseConnection()
def dataReceived(self, data): if data == "\r": data = "\r\n" return LineReceiver.dataReceived(self, data)
def dataReceived(self, data): LineReceiver.dataReceived(self, data)
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
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
def dataReceived(self, data): if data == "\r": data = "\r\n" return LineReceiver.dataReceived(self, data)
def dataReceived(self, data): # translate '\r' into '\n' return LineReceiver.dataReceived(self, data.replace('\r', '\n'))
def dataReceived(self, data): self.resetTimeout() LineReceiver.dataReceived(self, data)