15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#! python 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Python Serial Port Extension for Win32, Linux, BSD, Jython 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# see __init__.py 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# This module implements a loop back connection receiving itself what it sent. 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# The purpose of this module is.. well... You can run the unit tests with it. 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# and it was so easy to implement ;-) 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# (C) 2001-2011 Chris Liechti <cliechti@gmx.net> 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# this is distributed under a free software license, see license.txt 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# URL format: loop://[option[/option...]] 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# options: 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# - "debug" print diagnostic messages 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from serial.serialutil import * 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import threading 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import time 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import logging 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# map log level names to constants. used in fromURL() 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LOGGER_LEVELS = { 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'debug': logging.DEBUG, 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'info': logging.INFO, 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'warning': logging.WARNING, 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'error': logging.ERROR, 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class LoopbackSerial(SerialBase): 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Serial port implementation that simulates a loop back connection in plain software.""" 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9600, 19200, 38400, 57600, 115200) 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def open(self): 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Open port with current settings. This may throw a SerialException 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if the port cannot be opened.""" 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self._isOpen: 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise SerialException("Port is already open.") 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger = None 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock = threading.Lock() 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.loop_buffer = bytearray() 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.cts = False 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.dsr = False 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self._port is None: 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise SerialException("Port must be configured before it can be used.") 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # not that there is anything to open, but the function applies the 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # options found in the URL 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.fromURL(self.port) 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # not that there anything to configure... 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._reconfigurePort() 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # all things set up get, now a clean start 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._isOpen = True 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._rtscts: 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.setRTS(True) 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.setDTR(True) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.flushInput() 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.flushOutput() 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def _reconfigurePort(self): 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Set communication parameters on opened port. for the loop:// 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protocol all settings are ignored!""" 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # not that's it of any real use, but it helps in the unit tests 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not isinstance(self._baudrate, (int, long)) or not 0 < self._baudrate < 2**32: 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise ValueError("invalid baudrate: %r" % (self._baudrate)) 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('_reconfigurePort()') 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def close(self): 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Close port""" 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self._isOpen: 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._isOpen = False 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # in case of quick reconnects, give the server some time 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) time.sleep(0.3) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def makeDeviceName(self, port): 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise SerialException("there is no sensible way to turn numbers into URLs") 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def fromURL(self, url): 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """extract host and port from an URL string""" 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if url.lower().startswith("loop://"): url = url[7:] 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try: 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # process options now, directly altering self 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for option in url.split('/'): 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if '=' in option: 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) option, value = option.split('=', 1) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) value = None 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not option: 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pass 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) elif option == 'logging': 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) logging.basicConfig() # XXX is that good to call it here? 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger = logging.getLogger('pySerial.loop') 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.setLevel(LOGGER_LEVELS[value]) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.debug('enabled logging') 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise ValueError('unknown option: %r' % (option,)) 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) except ValueError, e: 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise SerialException('expected a string in the form "[loop://][option[/option...]]": %s' % e) 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # - - - - - - - - - - - - - - - - - - - - - - - - 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def inWaiting(self): 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Return the number of characters currently in the input buffer.""" 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # attention the logged value can differ from return value in 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # threaded environments... 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.debug('inWaiting() -> %d' % (len(self.loop_buffer),)) 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return len(self.loop_buffer) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def read(self, size=1): 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Read size bytes from the serial port. If a timeout is set it may 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return less characters as requested. With no timeout it will block 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) until the requested number of bytes is read.""" 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self._timeout is not None: 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timeout = time.time() + self._timeout 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timeout = None 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) data = bytearray() 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while size > 0: 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock.acquire() 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try: 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) block = to_bytes(self.loop_buffer[:size]) 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) del self.loop_buffer[:size] 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finally: 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock.release() 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) data += block 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size -= len(block) 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # check for timeout now, after data has been read. 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # useful for timeout = 0 (non blocking) read 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if timeout and time.time() > timeout: 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return bytes(data) 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def write(self, data): 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Output the given string over the serial port. Can block if the 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) connection is blocked. May raise SerialException if the connection is 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) closed.""" 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # ensure we're working with bytes 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) data = to_bytes(data) 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # calculate aprox time that would be used to send the data 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) time_used_to_send = 10.0*len(data) / self._baudrate 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # when a write timeout is configured check if we would be successful 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # (not sending anything, not even the part that would have time) 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self._writeTimeout is not None and time_used_to_send > self._writeTimeout: 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) time.sleep(self._writeTimeout) # must wait so that unit test succeeds 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise writeTimeoutError 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock.acquire() 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try: 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.loop_buffer += data 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finally: 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock.release() 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return len(data) 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def flushInput(self): 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Clear input buffer, discarding all that is in the buffer.""" 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('flushInput()') 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock.acquire() 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try: 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) del self.loop_buffer[:] 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finally: 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.buffer_lock.release() 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def flushOutput(self): 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Clear output buffer, aborting the current output and 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) discarding all that is in the buffer.""" 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('flushOutput()') 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def sendBreak(self, duration=0.25): 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Send break condition. Timed, returns to idle state after given 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) duration.""" 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def setBreak(self, level=True): 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Set break: Controls TXD. When active, to transmitting is 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) possible.""" 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('setBreak(%r)' % (level,)) 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def setRTS(self, level=True): 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Set terminal status line: Request To Send""" 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('setRTS(%r) -> state of CTS' % (level,)) 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.cts = level 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def setDTR(self, level=True): 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Set terminal status line: Data Terminal Ready""" 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('setDTR(%r) -> state of DSR' % (level,)) 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.dsr = level 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def getCTS(self): 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Read terminal status line: Clear To Send""" 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('getCTS() -> state of RTS (%r)' % (self.cts,)) 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return self.cts 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def getDSR(self): 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Read terminal status line: Data Set Ready""" 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('getDSR() -> state of DTR (%r)' % (self.dsr,)) 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return self.dsr 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def getRI(self): 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Read terminal status line: Ring Indicator""" 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('returning dummy for getRI()') 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return False 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def getCD(self): 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Read terminal status line: Carrier Detect""" 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not self._isOpen: raise portNotOpenError 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.logger: 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.logger.info('returning dummy for getCD()') 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return True 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # - - - platform specific - - - 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # None so far 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# assemble Serial class with the platform specific implementation and the base 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# for file-like behavior. for Python 2.6 and newer, that provide the new I/O 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# library, derive from io.RawIOBase 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)try: 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) import io 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)except ImportError: 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # classic version with our own file-like emulation 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) class Serial(LoopbackSerial, FileLike): 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pass 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)else: 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # io library present 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) class Serial(LoopbackSerial, io.RawIOBase): 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pass 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# simple client test 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)if __name__ == '__main__': 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) import sys 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) s = Serial('loop://') 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sys.stdout.write('%s\n' % s) 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sys.stdout.write("write...\n") 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) s.write("hello\n") 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) s.flush() 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sys.stdout.write("read: %s\n" % s.read(5)) 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) s.close() 266