OLD | NEW |
(Empty) | |
| 1 #! python |
| 2 # Python Serial Port Extension for Win32, Linux, BSD, Jython |
| 3 # see __init__.py |
| 4 # |
| 5 # (C) 2001-2010 Chris Liechti <cliechti@gmx.net> |
| 6 # this is distributed under a free software license, see license.txt |
| 7 |
| 8 # compatibility for older Python < 2.6 |
| 9 try: |
| 10 bytes |
| 11 bytearray |
| 12 except (NameError, AttributeError): |
| 13 # Python older than 2.6 do not have these types. Like for Python 2.6 they |
| 14 # should behave like str. For Python older than 3.0 we want to work with |
| 15 # strings anyway, only later versions have a true bytes type. |
| 16 bytes = str |
| 17 # bytearray is a mutable type that is easily turned into an instance of |
| 18 # bytes |
| 19 class bytearray(list): |
| 20 # for bytes(bytearray()) usage |
| 21 def __str__(self): return ''.join(self) |
| 22 def __repr__(self): return 'bytearray(%r)' % ''.join(self) |
| 23 # append automatically converts integers to characters |
| 24 def append(self, item): |
| 25 if isinstance(item, str): |
| 26 list.append(self, item) |
| 27 else: |
| 28 list.append(self, chr(item)) |
| 29 # += |
| 30 def __iadd__(self, other): |
| 31 for byte in other: |
| 32 self.append(byte) |
| 33 return self |
| 34 |
| 35 def __getslice__(self, i, j): |
| 36 return bytearray(list.__getslice__(self, i, j)) |
| 37 |
| 38 def __getitem__(self, item): |
| 39 if isinstance(item, slice): |
| 40 return bytearray(list.__getitem__(self, item)) |
| 41 else: |
| 42 return ord(list.__getitem__(self, item)) |
| 43 |
| 44 def __eq__(self, other): |
| 45 if isinstance(other, basestring): |
| 46 other = bytearray(other) |
| 47 return list.__eq__(self, other) |
| 48 |
| 49 # ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)`` |
| 50 # isn't returning the contents (very unfortunate). Therefore we need special |
| 51 # cases and test for it. Ensure that there is a ``memoryview`` object for older |
| 52 # Python versions. This is easier than making every test dependent on its |
| 53 # existence. |
| 54 try: |
| 55 memoryview |
| 56 except (NameError, AttributeError): |
| 57 # implementation does not matter as we do not realy use it. |
| 58 # it just must not inherit from something else we might care for. |
| 59 class memoryview: |
| 60 pass |
| 61 |
| 62 |
| 63 # all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11
' |
| 64 # so a simple ``bytes(sequence)`` doesn't work for all versions |
| 65 def to_bytes(seq): |
| 66 """convert a sequence to a bytes type""" |
| 67 if isinstance(seq, bytes): |
| 68 return seq |
| 69 elif isinstance(seq, bytearray): |
| 70 return bytes(seq) |
| 71 elif isinstance(seq, memoryview): |
| 72 return seq.tobytes() |
| 73 else: |
| 74 b = bytearray() |
| 75 for item in seq: |
| 76 b.append(item) # this one handles int and str for our emulation and
ints for Python 3.x |
| 77 return bytes(b) |
| 78 |
| 79 # create control bytes |
| 80 XON = to_bytes([17]) |
| 81 XOFF = to_bytes([19]) |
| 82 |
| 83 CR = to_bytes([13]) |
| 84 LF = to_bytes([10]) |
| 85 |
| 86 |
| 87 PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O',
'M', 'S' |
| 88 STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2) |
| 89 FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8) |
| 90 |
| 91 PARITY_NAMES = { |
| 92 PARITY_NONE: 'None', |
| 93 PARITY_EVEN: 'Even', |
| 94 PARITY_ODD: 'Odd', |
| 95 PARITY_MARK: 'Mark', |
| 96 PARITY_SPACE: 'Space', |
| 97 } |
| 98 |
| 99 |
| 100 class SerialException(IOError): |
| 101 """Base class for serial port related exceptions.""" |
| 102 |
| 103 |
| 104 class SerialTimeoutException(SerialException): |
| 105 """Write timeouts give an exception""" |
| 106 |
| 107 |
| 108 writeTimeoutError = SerialTimeoutException('Write timeout') |
| 109 portNotOpenError = SerialException('Attempting to use a port that is not open') |
| 110 |
| 111 |
| 112 class FileLike(object): |
| 113 """An abstract file like class. |
| 114 |
| 115 This class implements readline and readlines based on read and |
| 116 writelines based on write. |
| 117 This class is used to provide the above functions for to Serial |
| 118 port objects. |
| 119 |
| 120 Note that when the serial port was opened with _NO_ timeout that |
| 121 readline blocks until it sees a newline (or the specified size is |
| 122 reached) and that readlines would never return and therefore |
| 123 refuses to work (it raises an exception in this case)! |
| 124 """ |
| 125 |
| 126 def __init__(self): |
| 127 self.closed = True |
| 128 |
| 129 def close(self): |
| 130 self.closed = True |
| 131 |
| 132 # so that ports are closed when objects are discarded |
| 133 def __del__(self): |
| 134 """Destructor. Calls close().""" |
| 135 # The try/except block is in case this is called at program |
| 136 # exit time, when it's possible that globals have already been |
| 137 # deleted, and then the close() call might fail. Since |
| 138 # there's nothing we can do about such failures and they annoy |
| 139 # the end users, we suppress the traceback. |
| 140 try: |
| 141 self.close() |
| 142 except: |
| 143 pass |
| 144 |
| 145 def writelines(self, sequence): |
| 146 for line in sequence: |
| 147 self.write(line) |
| 148 |
| 149 def flush(self): |
| 150 """flush of file like objects""" |
| 151 pass |
| 152 |
| 153 # iterator for e.g. "for line in Serial(0): ..." usage |
| 154 def next(self): |
| 155 line = self.readline() |
| 156 if not line: raise StopIteration |
| 157 return line |
| 158 |
| 159 def __iter__(self): |
| 160 return self |
| 161 |
| 162 def readline(self, size=None, eol=LF): |
| 163 """read a line which is terminated with end-of-line (eol) character |
| 164 ('\n' by default) or until timeout.""" |
| 165 leneol = len(eol) |
| 166 line = bytearray() |
| 167 while True: |
| 168 c = self.read(1) |
| 169 if c: |
| 170 line += c |
| 171 if line[-leneol:] == eol: |
| 172 break |
| 173 if size is not None and len(line) >= size: |
| 174 break |
| 175 else: |
| 176 break |
| 177 return bytes(line) |
| 178 |
| 179 def readlines(self, sizehint=None, eol=LF): |
| 180 """read a list of lines, until timeout. |
| 181 sizehint is ignored.""" |
| 182 if self.timeout is None: |
| 183 raise ValueError("Serial port MUST have enabled timeout for this fun
ction!") |
| 184 leneol = len(eol) |
| 185 lines = [] |
| 186 while True: |
| 187 line = self.readline(eol=eol) |
| 188 if line: |
| 189 lines.append(line) |
| 190 if line[-leneol:] != eol: # was the line received with a time
out? |
| 191 break |
| 192 else: |
| 193 break |
| 194 return lines |
| 195 |
| 196 def xreadlines(self, sizehint=None): |
| 197 """Read lines, implemented as generator. It will raise StopIteration on |
| 198 timeout (empty read). sizehint is ignored.""" |
| 199 while True: |
| 200 line = self.readline() |
| 201 if not line: break |
| 202 yield line |
| 203 |
| 204 # other functions of file-likes - not used by pySerial |
| 205 |
| 206 #~ readinto(b) |
| 207 |
| 208 def seek(self, pos, whence=0): |
| 209 raise IOError("file is not seekable") |
| 210 |
| 211 def tell(self): |
| 212 raise IOError("file is not seekable") |
| 213 |
| 214 def truncate(self, n=None): |
| 215 raise IOError("file is not seekable") |
| 216 |
| 217 def isatty(self): |
| 218 return False |
| 219 |
| 220 |
| 221 class SerialBase(object): |
| 222 """Serial port base class. Provides __init__ function and properties to |
| 223 get/set port settings.""" |
| 224 |
| 225 # default values, may be overridden in subclasses that do not support all va
lues |
| 226 BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, |
| 227 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, |
| 228 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, |
| 229 3000000, 3500000, 4000000) |
| 230 BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS) |
| 231 PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE
) |
| 232 STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO) |
| 233 |
| 234 def __init__(self, |
| 235 port = None, # number of device, numbering starts at |
| 236 # zero. if everything fails, the user |
| 237 # can specify a device string, note |
| 238 # that this isn't portable anymore |
| 239 # port will be opened if one is specifie
d |
| 240 baudrate=9600, # baud rate |
| 241 bytesize=EIGHTBITS, # number of data bits |
| 242 parity=PARITY_NONE, # enable parity checking |
| 243 stopbits=STOPBITS_ONE, # number of stop bits |
| 244 timeout=None, # set a timeout value, None to wait fore
ver |
| 245 xonxoff=False, # enable software flow control |
| 246 rtscts=False, # enable RTS/CTS flow control |
| 247 writeTimeout=None, # set a timeout for writes |
| 248 dsrdtr=False, # None: use rtscts setting, dsrdtr overr
ide if True or False |
| 249 interCharTimeout=None # Inter-character timeout, None to disab
le |
| 250 ): |
| 251 """Initialize comm port object. If a port is given, then the port will b
e |
| 252 opened immediately. Otherwise a Serial port object in closed state |
| 253 is returned.""" |
| 254 |
| 255 self._isOpen = False |
| 256 self._port = None # correct value is assigned below throug
h properties |
| 257 self._baudrate = None # correct value is assigned below throug
h properties |
| 258 self._bytesize = None # correct value is assigned below throug
h properties |
| 259 self._parity = None # correct value is assigned below throug
h properties |
| 260 self._stopbits = None # correct value is assigned below throug
h properties |
| 261 self._timeout = None # correct value is assigned below throug
h properties |
| 262 self._writeTimeout = None # correct value is assigned below throug
h properties |
| 263 self._xonxoff = None # correct value is assigned below throug
h properties |
| 264 self._rtscts = None # correct value is assigned below throug
h properties |
| 265 self._dsrdtr = None # correct value is assigned below throug
h properties |
| 266 self._interCharTimeout = None # correct value is assigned below throug
h properties |
| 267 |
| 268 # assign values using get/set methods using the properties feature |
| 269 self.port = port |
| 270 self.baudrate = baudrate |
| 271 self.bytesize = bytesize |
| 272 self.parity = parity |
| 273 self.stopbits = stopbits |
| 274 self.timeout = timeout |
| 275 self.writeTimeout = writeTimeout |
| 276 self.xonxoff = xonxoff |
| 277 self.rtscts = rtscts |
| 278 self.dsrdtr = dsrdtr |
| 279 self.interCharTimeout = interCharTimeout |
| 280 |
| 281 if port is not None: |
| 282 self.open() |
| 283 |
| 284 def isOpen(self): |
| 285 """Check if the port is opened.""" |
| 286 return self._isOpen |
| 287 |
| 288 # - - - - - - - - - - - - - - - - - - - - - - - - |
| 289 |
| 290 # TODO: these are not really needed as the is the BAUDRATES etc. attribute..
. |
| 291 # maybe i remove them before the final release... |
| 292 |
| 293 def getSupportedBaudrates(self): |
| 294 return [(str(b), b) for b in self.BAUDRATES] |
| 295 |
| 296 def getSupportedByteSizes(self): |
| 297 return [(str(b), b) for b in self.BYTESIZES] |
| 298 |
| 299 def getSupportedStopbits(self): |
| 300 return [(str(b), b) for b in self.STOPBITS] |
| 301 |
| 302 def getSupportedParities(self): |
| 303 return [(PARITY_NAMES[b], b) for b in self.PARITIES] |
| 304 |
| 305 # - - - - - - - - - - - - - - - - - - - - - - - - |
| 306 |
| 307 def setPort(self, port): |
| 308 """Change the port. The attribute portstr is set to a string that |
| 309 contains the name of the port.""" |
| 310 |
| 311 was_open = self._isOpen |
| 312 if was_open: self.close() |
| 313 if port is not None: |
| 314 if isinstance(port, basestring): |
| 315 self.portstr = port |
| 316 else: |
| 317 self.portstr = self.makeDeviceName(port) |
| 318 else: |
| 319 self.portstr = None |
| 320 self._port = port |
| 321 self.name = self.portstr |
| 322 if was_open: self.open() |
| 323 |
| 324 def getPort(self): |
| 325 """Get the current port setting. The value that was passed on init or us
ing |
| 326 setPort() is passed back. See also the attribute portstr which contai
ns |
| 327 the name of the port as a string.""" |
| 328 return self._port |
| 329 |
| 330 port = property(getPort, setPort, doc="Port setting") |
| 331 |
| 332 |
| 333 def setBaudrate(self, baudrate): |
| 334 """Change baud rate. It raises a ValueError if the port is open and the |
| 335 baud rate is not possible. If the port is closed, then the value is |
| 336 accepted and the exception is raised when the port is opened.""" |
| 337 try: |
| 338 b = int(baudrate) |
| 339 except TypeError: |
| 340 raise ValueError("Not a valid baudrate: %r" % (baudrate,)) |
| 341 else: |
| 342 if b <= 0: |
| 343 raise ValueError("Not a valid baudrate: %r" % (baudrate,)) |
| 344 self._baudrate = b |
| 345 if self._isOpen: self._reconfigurePort() |
| 346 |
| 347 def getBaudrate(self): |
| 348 """Get the current baud rate setting.""" |
| 349 return self._baudrate |
| 350 |
| 351 baudrate = property(getBaudrate, setBaudrate, doc="Baud rate setting") |
| 352 |
| 353 |
| 354 def setByteSize(self, bytesize): |
| 355 """Change byte size.""" |
| 356 if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte si
ze: %r" % (bytesize,)) |
| 357 self._bytesize = bytesize |
| 358 if self._isOpen: self._reconfigurePort() |
| 359 |
| 360 def getByteSize(self): |
| 361 """Get the current byte size setting.""" |
| 362 return self._bytesize |
| 363 |
| 364 bytesize = property(getByteSize, setByteSize, doc="Byte size setting") |
| 365 |
| 366 |
| 367 def setParity(self, parity): |
| 368 """Change parity setting.""" |
| 369 if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r
" % (parity,)) |
| 370 self._parity = parity |
| 371 if self._isOpen: self._reconfigurePort() |
| 372 |
| 373 def getParity(self): |
| 374 """Get the current parity setting.""" |
| 375 return self._parity |
| 376 |
| 377 parity = property(getParity, setParity, doc="Parity setting") |
| 378 |
| 379 |
| 380 def setStopbits(self, stopbits): |
| 381 """Change stop bits size.""" |
| 382 if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit
size: %r" % (stopbits,)) |
| 383 self._stopbits = stopbits |
| 384 if self._isOpen: self._reconfigurePort() |
| 385 |
| 386 def getStopbits(self): |
| 387 """Get the current stop bits setting.""" |
| 388 return self._stopbits |
| 389 |
| 390 stopbits = property(getStopbits, setStopbits, doc="Stop bits setting") |
| 391 |
| 392 |
| 393 def setTimeout(self, timeout): |
| 394 """Change timeout setting.""" |
| 395 if timeout is not None: |
| 396 try: |
| 397 timeout + 1 # test if it's a number, will throw a TypeError
if not... |
| 398 except TypeError: |
| 399 raise ValueError("Not a valid timeout: %r" % (timeout,)) |
| 400 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeou
t,)) |
| 401 self._timeout = timeout |
| 402 if self._isOpen: self._reconfigurePort() |
| 403 |
| 404 def getTimeout(self): |
| 405 """Get the current timeout setting.""" |
| 406 return self._timeout |
| 407 |
| 408 timeout = property(getTimeout, setTimeout, doc="Timeout setting for read()") |
| 409 |
| 410 |
| 411 def setWriteTimeout(self, timeout): |
| 412 """Change timeout setting.""" |
| 413 if timeout is not None: |
| 414 if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeou
t,)) |
| 415 try: |
| 416 timeout + 1 #test if it's a number, will throw a TypeError i
f not... |
| 417 except TypeError: |
| 418 raise ValueError("Not a valid timeout: %r" % timeout) |
| 419 |
| 420 self._writeTimeout = timeout |
| 421 if self._isOpen: self._reconfigurePort() |
| 422 |
| 423 def getWriteTimeout(self): |
| 424 """Get the current timeout setting.""" |
| 425 return self._writeTimeout |
| 426 |
| 427 writeTimeout = property(getWriteTimeout, setWriteTimeout, doc="Timeout setti
ng for write()") |
| 428 |
| 429 |
| 430 def setXonXoff(self, xonxoff): |
| 431 """Change XON/XOFF setting.""" |
| 432 self._xonxoff = xonxoff |
| 433 if self._isOpen: self._reconfigurePort() |
| 434 |
| 435 def getXonXoff(self): |
| 436 """Get the current XON/XOFF setting.""" |
| 437 return self._xonxoff |
| 438 |
| 439 xonxoff = property(getXonXoff, setXonXoff, doc="XON/XOFF setting") |
| 440 |
| 441 def setRtsCts(self, rtscts): |
| 442 """Change RTS/CTS flow control setting.""" |
| 443 self._rtscts = rtscts |
| 444 if self._isOpen: self._reconfigurePort() |
| 445 |
| 446 def getRtsCts(self): |
| 447 """Get the current RTS/CTS flow control setting.""" |
| 448 return self._rtscts |
| 449 |
| 450 rtscts = property(getRtsCts, setRtsCts, doc="RTS/CTS flow control setting") |
| 451 |
| 452 def setDsrDtr(self, dsrdtr=None): |
| 453 """Change DsrDtr flow control setting.""" |
| 454 if dsrdtr is None: |
| 455 # if not set, keep backwards compatibility and follow rtscts setting |
| 456 self._dsrdtr = self._rtscts |
| 457 else: |
| 458 # if defined independently, follow its value |
| 459 self._dsrdtr = dsrdtr |
| 460 if self._isOpen: self._reconfigurePort() |
| 461 |
| 462 def getDsrDtr(self): |
| 463 """Get the current DSR/DTR flow control setting.""" |
| 464 return self._dsrdtr |
| 465 |
| 466 dsrdtr = property(getDsrDtr, setDsrDtr, "DSR/DTR flow control setting") |
| 467 |
| 468 def setInterCharTimeout(self, interCharTimeout): |
| 469 """Change inter-character timeout setting.""" |
| 470 if interCharTimeout is not None: |
| 471 if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r"
% interCharTimeout) |
| 472 try: |
| 473 interCharTimeout + 1 # test if it's a number, will throw a T
ypeError if not... |
| 474 except TypeError: |
| 475 raise ValueError("Not a valid timeout: %r" % interCharTimeout) |
| 476 |
| 477 self._interCharTimeout = interCharTimeout |
| 478 if self._isOpen: self._reconfigurePort() |
| 479 |
| 480 def getInterCharTimeout(self): |
| 481 """Get the current inter-character timeout setting.""" |
| 482 return self._interCharTimeout |
| 483 |
| 484 interCharTimeout = property(getInterCharTimeout, setInterCharTimeout, doc="I
nter-character timeout setting for read()") |
| 485 |
| 486 # - - - - - - - - - - - - - - - - - - - - - - - - |
| 487 |
| 488 _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff', |
| 489 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout') |
| 490 |
| 491 def getSettingsDict(self): |
| 492 """Get current port settings as a dictionary. For use with |
| 493 applySettingsDict""" |
| 494 return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS]) |
| 495 |
| 496 def applySettingsDict(self, d): |
| 497 """apply stored settings from a dictionary returned from |
| 498 getSettingsDict. it's allowed to delete keys from the dictionary. these |
| 499 values will simply left unchanged.""" |
| 500 for key in self._SETTINGS: |
| 501 if d[key] != getattr(self, '_'+key): # check against internal "_"
value |
| 502 setattr(self, key, d[key]) # set non "_" value to use p
roperties write function |
| 503 |
| 504 # - - - - - - - - - - - - - - - - - - - - - - - - |
| 505 |
| 506 def __repr__(self): |
| 507 """String representation of the current port settings and its state.""" |
| 508 return "%s<id=0x%x, open=%s>(port=%r, baudrate=%r, bytesize=%r, parity=%
r, stopbits=%r, timeout=%r, xonxoff=%r, rtscts=%r, dsrdtr=%r)" % ( |
| 509 self.__class__.__name__, |
| 510 id(self), |
| 511 self._isOpen, |
| 512 self.portstr, |
| 513 self.baudrate, |
| 514 self.bytesize, |
| 515 self.parity, |
| 516 self.stopbits, |
| 517 self.timeout, |
| 518 self.xonxoff, |
| 519 self.rtscts, |
| 520 self.dsrdtr, |
| 521 ) |
| 522 |
| 523 |
| 524 # - - - - - - - - - - - - - - - - - - - - - - - - |
| 525 # compatibility with io library |
| 526 |
| 527 def readable(self): return True |
| 528 def writable(self): return True |
| 529 def seekable(self): return False |
| 530 def readinto(self, b): |
| 531 data = self.read(len(b)) |
| 532 n = len(data) |
| 533 try: |
| 534 b[:n] = data |
| 535 except TypeError, err: |
| 536 import array |
| 537 if not isinstance(b, array.array): |
| 538 raise err |
| 539 b[:n] = array.array('b', data) |
| 540 return n |
| 541 |
| 542 |
| 543 if __name__ == '__main__': |
| 544 import sys |
| 545 s = SerialBase() |
| 546 sys.stdout.write('port name: %s\n' % s.portstr) |
| 547 sys.stdout.write('baud rates: %s\n' % s.getSupportedBaudrates()) |
| 548 sys.stdout.write('byte sizes: %s\n' % s.getSupportedByteSizes()) |
| 549 sys.stdout.write('parities: %s\n' % s.getSupportedParities()) |
| 550 sys.stdout.write('stop bits: %s\n' % s.getSupportedStopbits()) |
| 551 sys.stdout.write('%s\n' % s) |
OLD | NEW |