OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Python Serial Port Extension for Win32, Linux, BSD, Jython |
| 4 # module for serial IO for POSIX compatible systems, like Linux |
| 5 # see __init__.py |
| 6 # |
| 7 # (C) 2001-2010 Chris Liechti <cliechti@gmx.net> |
| 8 # this is distributed under a free software license, see license.txt |
| 9 # |
| 10 # parts based on code from Grant B. Edwards <grante@visi.com>: |
| 11 # ftp://ftp.visi.com/users/grante/python/PosixSerial.py |
| 12 # |
| 13 # references: http://www.easysw.com/~mike/serial/serial.html |
| 14 |
| 15 import sys, os, fcntl, termios, struct, select, errno, time |
| 16 from serial.serialutil import * |
| 17 |
| 18 # Do check the Python version as some constants have moved. |
| 19 if (sys.hexversion < 0x020100f0): |
| 20 import TERMIOS |
| 21 else: |
| 22 TERMIOS = termios |
| 23 |
| 24 if (sys.hexversion < 0x020200f0): |
| 25 import FCNTL |
| 26 else: |
| 27 FCNTL = fcntl |
| 28 |
| 29 # try to detect the OS so that a device can be selected... |
| 30 # this code block should supply a device() and set_special_baudrate() function |
| 31 # for the platform |
| 32 plat = sys.platform.lower() |
| 33 |
| 34 if plat[:5] == 'linux': # Linux (confirmed) |
| 35 |
| 36 def device(port): |
| 37 return '/dev/ttyS%d' % port |
| 38 |
| 39 TCGETS2 = 0x802C542A |
| 40 TCSETS2 = 0x402C542B |
| 41 BOTHER = 0o010000 |
| 42 |
| 43 def set_special_baudrate(port, baudrate): |
| 44 # right size is 44 on x86_64, allow for some growth |
| 45 import array |
| 46 buf = array.array('i', [0] * 64) |
| 47 |
| 48 try: |
| 49 # get serial_struct |
| 50 FCNTL.ioctl(port.fd, TCGETS2, buf) |
| 51 # set custom speed |
| 52 buf[2] &= ~TERMIOS.CBAUD |
| 53 buf[2] |= BOTHER |
| 54 buf[9] = buf[10] = baudrate |
| 55 |
| 56 # set serial_struct |
| 57 res = FCNTL.ioctl(port.fd, TCSETS2, buf) |
| 58 except IOError, e: |
| 59 raise ValueError('Failed to set custom baud rate (%s): %s' % (baudra
te, e)) |
| 60 |
| 61 baudrate_constants = { |
| 62 0: 0000000, # hang up |
| 63 50: 0000001, |
| 64 75: 0000002, |
| 65 110: 0000003, |
| 66 134: 0000004, |
| 67 150: 0000005, |
| 68 200: 0000006, |
| 69 300: 0000007, |
| 70 600: 0000010, |
| 71 1200: 0000011, |
| 72 1800: 0000012, |
| 73 2400: 0000013, |
| 74 4800: 0000014, |
| 75 9600: 0000015, |
| 76 19200: 0000016, |
| 77 38400: 0000017, |
| 78 57600: 0010001, |
| 79 115200: 0010002, |
| 80 230400: 0010003, |
| 81 460800: 0010004, |
| 82 500000: 0010005, |
| 83 576000: 0010006, |
| 84 921600: 0010007, |
| 85 1000000: 0010010, |
| 86 1152000: 0010011, |
| 87 1500000: 0010012, |
| 88 2000000: 0010013, |
| 89 2500000: 0010014, |
| 90 3000000: 0010015, |
| 91 3500000: 0010016, |
| 92 4000000: 0010017 |
| 93 } |
| 94 |
| 95 elif plat == 'cygwin': # cygwin/win32 (confirmed) |
| 96 |
| 97 def device(port): |
| 98 return '/dev/com%d' % (port + 1) |
| 99 |
| 100 def set_special_baudrate(port, baudrate): |
| 101 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 102 |
| 103 baudrate_constants = { |
| 104 128000: 0x01003, |
| 105 256000: 0x01005, |
| 106 500000: 0x01007, |
| 107 576000: 0x01008, |
| 108 921600: 0x01009, |
| 109 1000000: 0x0100a, |
| 110 1152000: 0x0100b, |
| 111 1500000: 0x0100c, |
| 112 2000000: 0x0100d, |
| 113 2500000: 0x0100e, |
| 114 3000000: 0x0100f |
| 115 } |
| 116 |
| 117 elif plat[:7] == 'openbsd': # OpenBSD |
| 118 |
| 119 def device(port): |
| 120 return '/dev/cua%02d' % port |
| 121 |
| 122 def set_special_baudrate(port, baudrate): |
| 123 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 124 |
| 125 baudrate_constants = {} |
| 126 |
| 127 elif plat[:3] == 'bsd' or \ |
| 128 plat[:7] == 'freebsd': |
| 129 |
| 130 def device(port): |
| 131 return '/dev/cuad%d' % port |
| 132 |
| 133 def set_special_baudrate(port, baudrate): |
| 134 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 135 |
| 136 baudrate_constants = {} |
| 137 |
| 138 elif plat[:6] == 'darwin': # OS X |
| 139 |
| 140 version = os.uname()[2].split('.') |
| 141 # Tiger or above can support arbitrary serial speeds |
| 142 if int(version[0]) >= 8: |
| 143 def set_special_baudrate(port, baudrate): |
| 144 # use IOKit-specific call to set up high speeds |
| 145 import array, fcntl |
| 146 buf = array.array('i', [baudrate]) |
| 147 IOSSIOSPEED = 0x80045402 #_IOW('T', 2, speed_t) |
| 148 fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1) |
| 149 else: # version < 8 |
| 150 def set_special_baudrate(port, baudrate): |
| 151 raise ValueError("baud rate not supported") |
| 152 |
| 153 def device(port): |
| 154 return '/dev/cuad%d' % port |
| 155 |
| 156 baudrate_constants = {} |
| 157 |
| 158 |
| 159 elif plat[:6] == 'netbsd': # NetBSD 1.6 testing by Erk |
| 160 |
| 161 def device(port): |
| 162 return '/dev/dty%02d' % port |
| 163 |
| 164 def set_special_baudrate(port, baudrate): |
| 165 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 166 |
| 167 baudrate_constants = {} |
| 168 |
| 169 elif plat[:4] == 'irix': # IRIX (partially tested) |
| 170 |
| 171 def device(port): |
| 172 return '/dev/ttyf%d' % (port+1) #XXX different device names depending on
flow control |
| 173 |
| 174 def set_special_baudrate(port, baudrate): |
| 175 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 176 |
| 177 baudrate_constants = {} |
| 178 |
| 179 elif plat[:2] == 'hp': # HP-UX (not tested) |
| 180 |
| 181 def device(port): |
| 182 return '/dev/tty%dp0' % (port+1) |
| 183 |
| 184 def set_special_baudrate(port, baudrate): |
| 185 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 186 |
| 187 baudrate_constants = {} |
| 188 |
| 189 elif plat[:5] == 'sunos': # Solaris/SunOS (confirmed) |
| 190 |
| 191 def device(port): |
| 192 return '/dev/tty%c' % (ord('a')+port) |
| 193 |
| 194 def set_special_baudrate(port, baudrate): |
| 195 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 196 |
| 197 baudrate_constants = {} |
| 198 |
| 199 elif plat[:3] == 'aix': # AIX |
| 200 |
| 201 def device(port): |
| 202 return '/dev/tty%d' % (port) |
| 203 |
| 204 def set_special_baudrate(port, baudrate): |
| 205 raise ValueError("sorry don't know how to handle non standard baud rate
on this platform") |
| 206 |
| 207 baudrate_constants = {} |
| 208 |
| 209 else: |
| 210 # platform detection has failed... |
| 211 sys.stderr.write("""\ |
| 212 don't know how to number ttys on this system. |
| 213 ! Use an explicit path (eg /dev/ttyS1) or send this information to |
| 214 ! the author of this module: |
| 215 |
| 216 sys.platform = %r |
| 217 os.name = %r |
| 218 serialposix.py version = %s |
| 219 |
| 220 also add the device name of the serial port and where the |
| 221 counting starts for the first serial port. |
| 222 e.g. 'first serial port: /dev/ttyS0' |
| 223 and with a bit luck you can get this module running... |
| 224 """ % (sys.platform, os.name, VERSION)) |
| 225 # no exception, just continue with a brave attempt to build a device name |
| 226 # even if the device name is not correct for the platform it has chances |
| 227 # to work using a string with the real device name as port parameter. |
| 228 def device(portum): |
| 229 return '/dev/ttyS%d' % portnum |
| 230 def set_special_baudrate(port, baudrate): |
| 231 raise SerialException("sorry don't know how to handle non standard baud
rate on this platform") |
| 232 baudrate_constants = {} |
| 233 #~ raise Exception, "this module does not run on this platform, sorry." |
| 234 |
| 235 # whats up with "aix", "beos", .... |
| 236 # they should work, just need to know the device names. |
| 237 |
| 238 |
| 239 # load some constants for later use. |
| 240 # try to use values from TERMIOS, use defaults from linux otherwise |
| 241 TIOCMGET = hasattr(TERMIOS, 'TIOCMGET') and TERMIOS.TIOCMGET or 0x5415 |
| 242 TIOCMBIS = hasattr(TERMIOS, 'TIOCMBIS') and TERMIOS.TIOCMBIS or 0x5416 |
| 243 TIOCMBIC = hasattr(TERMIOS, 'TIOCMBIC') and TERMIOS.TIOCMBIC or 0x5417 |
| 244 TIOCMSET = hasattr(TERMIOS, 'TIOCMSET') and TERMIOS.TIOCMSET or 0x5418 |
| 245 |
| 246 #TIOCM_LE = hasattr(TERMIOS, 'TIOCM_LE') and TERMIOS.TIOCM_LE or 0x001 |
| 247 TIOCM_DTR = hasattr(TERMIOS, 'TIOCM_DTR') and TERMIOS.TIOCM_DTR or 0x002 |
| 248 TIOCM_RTS = hasattr(TERMIOS, 'TIOCM_RTS') and TERMIOS.TIOCM_RTS or 0x004 |
| 249 #TIOCM_ST = hasattr(TERMIOS, 'TIOCM_ST') and TERMIOS.TIOCM_ST or 0x008 |
| 250 #TIOCM_SR = hasattr(TERMIOS, 'TIOCM_SR') and TERMIOS.TIOCM_SR or 0x010 |
| 251 |
| 252 TIOCM_CTS = hasattr(TERMIOS, 'TIOCM_CTS') and TERMIOS.TIOCM_CTS or 0x020 |
| 253 TIOCM_CAR = hasattr(TERMIOS, 'TIOCM_CAR') and TERMIOS.TIOCM_CAR or 0x040 |
| 254 TIOCM_RNG = hasattr(TERMIOS, 'TIOCM_RNG') and TERMIOS.TIOCM_RNG or 0x080 |
| 255 TIOCM_DSR = hasattr(TERMIOS, 'TIOCM_DSR') and TERMIOS.TIOCM_DSR or 0x100 |
| 256 TIOCM_CD = hasattr(TERMIOS, 'TIOCM_CD') and TERMIOS.TIOCM_CD or TIOCM_CAR |
| 257 TIOCM_RI = hasattr(TERMIOS, 'TIOCM_RI') and TERMIOS.TIOCM_RI or TIOCM_RNG |
| 258 #TIOCM_OUT1 = hasattr(TERMIOS, 'TIOCM_OUT1') and TERMIOS.TIOCM_OUT1 or 0x2000 |
| 259 #TIOCM_OUT2 = hasattr(TERMIOS, 'TIOCM_OUT2') and TERMIOS.TIOCM_OUT2 or 0x4000 |
| 260 if hasattr(TERMIOS, 'TIOCINQ'): |
| 261 TIOCINQ = TERMIOS.TIOCINQ |
| 262 else: |
| 263 TIOCINQ = hasattr(TERMIOS, 'FIONREAD') and TERMIOS.FIONREAD or 0x541B |
| 264 TIOCOUTQ = hasattr(TERMIOS, 'TIOCOUTQ') and TERMIOS.TIOCOUTQ or 0x5411 |
| 265 |
| 266 TIOCM_zero_str = struct.pack('I', 0) |
| 267 TIOCM_RTS_str = struct.pack('I', TIOCM_RTS) |
| 268 TIOCM_DTR_str = struct.pack('I', TIOCM_DTR) |
| 269 |
| 270 TIOCSBRK = hasattr(TERMIOS, 'TIOCSBRK') and TERMIOS.TIOCSBRK or 0x5427 |
| 271 TIOCCBRK = hasattr(TERMIOS, 'TIOCCBRK') and TERMIOS.TIOCCBRK or 0x5428 |
| 272 |
| 273 |
| 274 class PosixSerial(SerialBase): |
| 275 """Serial port class POSIX implementation. Serial port configuration is |
| 276 done with termios and fcntl. Runs on Linux and many other Un*x like |
| 277 systems.""" |
| 278 |
| 279 def open(self): |
| 280 """Open port with current settings. This may throw a SerialException |
| 281 if the port cannot be opened.""" |
| 282 if self._port is None: |
| 283 raise SerialException("Port must be configured before it can be used
.") |
| 284 if self._isOpen: |
| 285 raise SerialException("Port is already open.") |
| 286 self.fd = None |
| 287 # open |
| 288 try: |
| 289 self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK) |
| 290 except IOError, msg: |
| 291 self.fd = None |
| 292 raise SerialException(msg.errno, "could not open port %s: %s" % (sel
f._port, msg)) |
| 293 #~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) # set blocking |
| 294 |
| 295 try: |
| 296 self._reconfigurePort() |
| 297 except: |
| 298 try: |
| 299 os.close(self.fd) |
| 300 except: |
| 301 # ignore any exception when closing the port |
| 302 # also to keep original exception that happened when setting up |
| 303 pass |
| 304 self.fd = None |
| 305 raise |
| 306 else: |
| 307 self._isOpen = True |
| 308 self.flushInput() |
| 309 |
| 310 |
| 311 def _reconfigurePort(self): |
| 312 """Set communication parameters on opened port.""" |
| 313 if self.fd is None: |
| 314 raise SerialException("Can only operate on a valid file descriptor") |
| 315 custom_baud = None |
| 316 |
| 317 vmin = vtime = 0 # timeout is done via select |
| 318 if self._interCharTimeout is not None: |
| 319 vmin = 1 |
| 320 vtime = int(self._interCharTimeout * 10) |
| 321 try: |
| 322 orig_attr = termios.tcgetattr(self.fd) |
| 323 iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr |
| 324 except termios.error, msg: # if a port is nonexistent but has a /de
v file, it'll fail here |
| 325 raise SerialException("Could not configure port: %s" % msg) |
| 326 # set up raw mode / no echo / binary |
| 327 cflag |= (TERMIOS.CLOCAL|TERMIOS.CREAD) |
| 328 lflag &= ~(TERMIOS.ICANON|TERMIOS.ECHO|TERMIOS.ECHOE|TERMIOS.ECHOK|TERMI
OS.ECHONL| |
| 329 TERMIOS.ISIG|TERMIOS.IEXTEN) #|TERMIOS.ECHOPRT |
| 330 for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk |
| 331 if hasattr(TERMIOS, flag): |
| 332 lflag &= ~getattr(TERMIOS, flag) |
| 333 |
| 334 oflag &= ~(TERMIOS.OPOST) |
| 335 iflag &= ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IGNBRK) |
| 336 if hasattr(TERMIOS, 'IUCLC'): |
| 337 iflag &= ~TERMIOS.IUCLC |
| 338 if hasattr(TERMIOS, 'PARMRK'): |
| 339 iflag &= ~TERMIOS.PARMRK |
| 340 |
| 341 # setup baud rate |
| 342 try: |
| 343 ispeed = ospeed = getattr(TERMIOS, 'B%s' % (self._baudrate)) |
| 344 except AttributeError: |
| 345 try: |
| 346 ispeed = ospeed = baudrate_constants[self._baudrate] |
| 347 except KeyError: |
| 348 #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) |
| 349 # may need custom baud rate, it isn't in our list. |
| 350 ispeed = ospeed = getattr(TERMIOS, 'B38400') |
| 351 try: |
| 352 custom_baud = int(self._baudrate) # store for later |
| 353 except ValueError: |
| 354 raise ValueError('Invalid baud rate: %r' % self._baudrate) |
| 355 else: |
| 356 if custom_baud < 0: |
| 357 raise ValueError('Invalid baud rate: %r' % self._baudrat
e) |
| 358 |
| 359 # setup char len |
| 360 cflag &= ~TERMIOS.CSIZE |
| 361 if self._bytesize == 8: |
| 362 cflag |= TERMIOS.CS8 |
| 363 elif self._bytesize == 7: |
| 364 cflag |= TERMIOS.CS7 |
| 365 elif self._bytesize == 6: |
| 366 cflag |= TERMIOS.CS6 |
| 367 elif self._bytesize == 5: |
| 368 cflag |= TERMIOS.CS5 |
| 369 else: |
| 370 raise ValueError('Invalid char len: %r' % self._bytesize) |
| 371 # setup stopbits |
| 372 if self._stopbits == STOPBITS_ONE: |
| 373 cflag &= ~(TERMIOS.CSTOPB) |
| 374 elif self._stopbits == STOPBITS_ONE_POINT_FIVE: |
| 375 cflag |= (TERMIOS.CSTOPB) # XXX same as TWO.. there is no POSIX su
pport for 1.5 |
| 376 elif self._stopbits == STOPBITS_TWO: |
| 377 cflag |= (TERMIOS.CSTOPB) |
| 378 else: |
| 379 raise ValueError('Invalid stop bit specification: %r' % self._stopbi
ts) |
| 380 # setup parity |
| 381 iflag &= ~(TERMIOS.INPCK|TERMIOS.ISTRIP) |
| 382 if self._parity == PARITY_NONE: |
| 383 cflag &= ~(TERMIOS.PARENB|TERMIOS.PARODD) |
| 384 elif self._parity == PARITY_EVEN: |
| 385 cflag &= ~(TERMIOS.PARODD) |
| 386 cflag |= (TERMIOS.PARENB) |
| 387 elif self._parity == PARITY_ODD: |
| 388 cflag |= (TERMIOS.PARENB|TERMIOS.PARODD) |
| 389 else: |
| 390 raise ValueError('Invalid parity: %r' % self._parity) |
| 391 # setup flow control |
| 392 # xonxoff |
| 393 if hasattr(TERMIOS, 'IXANY'): |
| 394 if self._xonxoff: |
| 395 iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) #|TERMIOS.IXANY) |
| 396 else: |
| 397 iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY) |
| 398 else: |
| 399 if self._xonxoff: |
| 400 iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) |
| 401 else: |
| 402 iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF) |
| 403 # rtscts |
| 404 if hasattr(TERMIOS, 'CRTSCTS'): |
| 405 if self._rtscts: |
| 406 cflag |= (TERMIOS.CRTSCTS) |
| 407 else: |
| 408 cflag &= ~(TERMIOS.CRTSCTS) |
| 409 elif hasattr(TERMIOS, 'CNEW_RTSCTS'): # try it with alternate constant
name |
| 410 if self._rtscts: |
| 411 cflag |= (TERMIOS.CNEW_RTSCTS) |
| 412 else: |
| 413 cflag &= ~(TERMIOS.CNEW_RTSCTS) |
| 414 # XXX should there be a warning if setting up rtscts (and xonxoff etc) f
ails?? |
| 415 |
| 416 # buffer |
| 417 # vmin "minimal number of characters to be read. = for non blocking" |
| 418 if vmin < 0 or vmin > 255: |
| 419 raise ValueError('Invalid vmin: %r ' % vmin) |
| 420 cc[TERMIOS.VMIN] = vmin |
| 421 # vtime |
| 422 if vtime < 0 or vtime > 255: |
| 423 raise ValueError('Invalid vtime: %r' % vtime) |
| 424 cc[TERMIOS.VTIME] = vtime |
| 425 # activate settings |
| 426 if [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr: |
| 427 termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lf
lag, ispeed, ospeed, cc]) |
| 428 |
| 429 # apply custom baud rate, if any |
| 430 if custom_baud is not None: |
| 431 set_special_baudrate(self, custom_baud) |
| 432 |
| 433 def close(self): |
| 434 """Close port""" |
| 435 if self._isOpen: |
| 436 if self.fd is not None: |
| 437 os.close(self.fd) |
| 438 self.fd = None |
| 439 self._isOpen = False |
| 440 |
| 441 def makeDeviceName(self, port): |
| 442 return device(port) |
| 443 |
| 444 # - - - - - - - - - - - - - - - - - - - - - - - - |
| 445 |
| 446 def inWaiting(self): |
| 447 """Return the number of characters currently in the input buffer.""" |
| 448 #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) |
| 449 s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str) |
| 450 return struct.unpack('I',s)[0] |
| 451 |
| 452 # select based implementation, proved to work on many systems |
| 453 def read(self, size=1): |
| 454 """Read size bytes from the serial port. If a timeout is set it may |
| 455 return less characters as requested. With no timeout it will block |
| 456 until the requested number of bytes is read.""" |
| 457 if not self._isOpen: raise portNotOpenError |
| 458 read = bytearray() |
| 459 while len(read) < size: |
| 460 try: |
| 461 ready,_,_ = select.select([self.fd],[],[], self._timeout) |
| 462 # If select was used with a timeout, and the timeout occurs, it |
| 463 # returns with empty lists -> thus abort read operation. |
| 464 # For timeout == 0 (non-blocking operation) also abort when ther
e |
| 465 # is nothing to read. |
| 466 if not ready: |
| 467 break # timeout |
| 468 buf = os.read(self.fd, size-len(read)) |
| 469 # read should always return some data as select reported it was |
| 470 # ready to read when we get to this point. |
| 471 if not buf: |
| 472 # Disconnected devices, at least on Linux, show the |
| 473 # behavior that they are always ready to read immediately |
| 474 # but reading returns nothing. |
| 475 raise SerialException('device reports readiness to read but
returned no data (device disconnected or multiple access on port?)') |
| 476 read.extend(buf) |
| 477 except select.error, e: |
| 478 # ignore EAGAIN errors. all other errors are shown |
| 479 # see also http://www.python.org/dev/peps/pep-3151/#select |
| 480 if e[0] != errno.EAGAIN: |
| 481 raise SerialException('read failed: %s' % (e,)) |
| 482 except OSError, e: |
| 483 # ignore EAGAIN errors. all other errors are shown |
| 484 if e.errno != errno.EAGAIN: |
| 485 raise SerialException('read failed: %s' % (e,)) |
| 486 return bytes(read) |
| 487 |
| 488 def write(self, data): |
| 489 """Output the given string over the serial port.""" |
| 490 if not self._isOpen: raise portNotOpenError |
| 491 d = to_bytes(data) |
| 492 tx_len = len(d) |
| 493 if self._writeTimeout is not None and self._writeTimeout > 0: |
| 494 timeout = time.time() + self._writeTimeout |
| 495 else: |
| 496 timeout = None |
| 497 while tx_len > 0: |
| 498 try: |
| 499 n = os.write(self.fd, d) |
| 500 if timeout: |
| 501 # when timeout is set, use select to wait for being ready |
| 502 # with the time left as timeout |
| 503 timeleft = timeout - time.time() |
| 504 if timeleft < 0: |
| 505 raise writeTimeoutError |
| 506 _, ready, _ = select.select([], [self.fd], [], timeleft) |
| 507 if not ready: |
| 508 raise writeTimeoutError |
| 509 else: |
| 510 # wait for write operation |
| 511 _, ready, _ = select.select([], [self.fd], [], None) |
| 512 if not ready: |
| 513 raise SerialException('write failed (select)') |
| 514 d = d[n:] |
| 515 tx_len -= n |
| 516 except OSError, v: |
| 517 if v.errno != errno.EAGAIN: |
| 518 raise SerialException('write failed: %s' % (v,)) |
| 519 return len(data) |
| 520 |
| 521 def flush(self): |
| 522 """Flush of file like objects. In this case, wait until all data |
| 523 is written.""" |
| 524 self.drainOutput() |
| 525 |
| 526 def flushInput(self): |
| 527 """Clear input buffer, discarding all that is in the buffer.""" |
| 528 if not self._isOpen: raise portNotOpenError |
| 529 termios.tcflush(self.fd, TERMIOS.TCIFLUSH) |
| 530 |
| 531 def flushOutput(self): |
| 532 """Clear output buffer, aborting the current output and |
| 533 discarding all that is in the buffer.""" |
| 534 if not self._isOpen: raise portNotOpenError |
| 535 termios.tcflush(self.fd, TERMIOS.TCOFLUSH) |
| 536 |
| 537 def sendBreak(self, duration=0.25): |
| 538 """Send break condition. Timed, returns to idle state after given durati
on.""" |
| 539 if not self._isOpen: raise portNotOpenError |
| 540 termios.tcsendbreak(self.fd, int(duration/0.25)) |
| 541 |
| 542 def setBreak(self, level=1): |
| 543 """Set break: Controls TXD. When active, no transmitting is possible.""" |
| 544 if self.fd is None: raise portNotOpenError |
| 545 if level: |
| 546 fcntl.ioctl(self.fd, TIOCSBRK) |
| 547 else: |
| 548 fcntl.ioctl(self.fd, TIOCCBRK) |
| 549 |
| 550 def setRTS(self, level=1): |
| 551 """Set terminal status line: Request To Send""" |
| 552 if not self._isOpen: raise portNotOpenError |
| 553 if level: |
| 554 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str) |
| 555 else: |
| 556 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str) |
| 557 |
| 558 def setDTR(self, level=1): |
| 559 """Set terminal status line: Data Terminal Ready""" |
| 560 if not self._isOpen: raise portNotOpenError |
| 561 if level: |
| 562 fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) |
| 563 else: |
| 564 fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str) |
| 565 |
| 566 def getCTS(self): |
| 567 """Read terminal status line: Clear To Send""" |
| 568 if not self._isOpen: raise portNotOpenError |
| 569 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) |
| 570 return struct.unpack('I',s)[0] & TIOCM_CTS != 0 |
| 571 |
| 572 def getDSR(self): |
| 573 """Read terminal status line: Data Set Ready""" |
| 574 if not self._isOpen: raise portNotOpenError |
| 575 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) |
| 576 return struct.unpack('I',s)[0] & TIOCM_DSR != 0 |
| 577 |
| 578 def getRI(self): |
| 579 """Read terminal status line: Ring Indicator""" |
| 580 if not self._isOpen: raise portNotOpenError |
| 581 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) |
| 582 return struct.unpack('I',s)[0] & TIOCM_RI != 0 |
| 583 |
| 584 def getCD(self): |
| 585 """Read terminal status line: Carrier Detect""" |
| 586 if not self._isOpen: raise portNotOpenError |
| 587 s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) |
| 588 return struct.unpack('I',s)[0] & TIOCM_CD != 0 |
| 589 |
| 590 # - - platform specific - - - - |
| 591 |
| 592 def outWaiting(self): |
| 593 """Return the number of characters currently in the output buffer.""" |
| 594 #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) |
| 595 s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str) |
| 596 return struct.unpack('I',s)[0] |
| 597 |
| 598 def drainOutput(self): |
| 599 """internal - not portable!""" |
| 600 if not self._isOpen: raise portNotOpenError |
| 601 termios.tcdrain(self.fd) |
| 602 |
| 603 def nonblocking(self): |
| 604 """internal - not portable!""" |
| 605 if not self._isOpen: raise portNotOpenError |
| 606 fcntl.fcntl(self.fd, FCNTL.F_SETFL, os.O_NONBLOCK) |
| 607 |
| 608 def fileno(self): |
| 609 """\ |
| 610 For easier use of the serial port instance with select. |
| 611 WARNING: this function is not portable to different platforms! |
| 612 """ |
| 613 if not self._isOpen: raise portNotOpenError |
| 614 return self.fd |
| 615 |
| 616 def setXON(self, level=True): |
| 617 """\ |
| 618 Manually control flow - when software flow control is enabled. |
| 619 This will send XON (true) and XOFF (false) to the other device. |
| 620 WARNING: this function is not portable to different platforms! |
| 621 """ |
| 622 if not self.hComPort: raise portNotOpenError |
| 623 if enable: |
| 624 termios.tcflow(self.fd, TERMIOS.TCION) |
| 625 else: |
| 626 termios.tcflow(self.fd, TERMIOS.TCIOFF) |
| 627 |
| 628 def flowControlOut(self, enable): |
| 629 """\ |
| 630 Manually control flow of outgoing data - when hardware or software flow |
| 631 control is enabled. |
| 632 WARNING: this function is not portable to different platforms! |
| 633 """ |
| 634 if not self._isOpen: raise portNotOpenError |
| 635 if enable: |
| 636 termios.tcflow(self.fd, TERMIOS.TCOON) |
| 637 else: |
| 638 termios.tcflow(self.fd, TERMIOS.TCOOFF) |
| 639 |
| 640 |
| 641 # assemble Serial class with the platform specifc implementation and the base |
| 642 # for file-like behavior. for Python 2.6 and newer, that provide the new I/O |
| 643 # library, derrive from io.RawIOBase |
| 644 try: |
| 645 import io |
| 646 except ImportError: |
| 647 # classic version with our own file-like emulation |
| 648 class Serial(PosixSerial, FileLike): |
| 649 pass |
| 650 else: |
| 651 # io library present |
| 652 class Serial(PosixSerial, io.RawIOBase): |
| 653 pass |
| 654 |
| 655 class PosixPollSerial(Serial): |
| 656 """poll based read implementation. not all systems support poll properly. |
| 657 however this one has better handling of errors, such as a device |
| 658 disconnecting while it's in use (e.g. USB-serial unplugged)""" |
| 659 |
| 660 def read(self, size=1): |
| 661 """Read size bytes from the serial port. If a timeout is set it may |
| 662 return less characters as requested. With no timeout it will block |
| 663 until the requested number of bytes is read.""" |
| 664 if self.fd is None: raise portNotOpenError |
| 665 read = bytearray() |
| 666 poll = select.poll() |
| 667 poll.register(self.fd, select.POLLIN|select.POLLERR|select.POLLHUP|selec
t.POLLNVAL) |
| 668 if size > 0: |
| 669 while len(read) < size: |
| 670 # print "\tread(): size",size, "have", len(read) #debug |
| 671 # wait until device becomes ready to read (or something fails) |
| 672 for fd, event in poll.poll(self._timeout*1000): |
| 673 if event & (select.POLLERR|select.POLLHUP|select.POLLNVAL): |
| 674 raise SerialException('device reports error (poll)') |
| 675 # we don't care if it is select.POLLIN or timeout, that's |
| 676 # handled below |
| 677 buf = os.read(self.fd, size - len(read)) |
| 678 read.extend(buf) |
| 679 if ((self._timeout is not None and self._timeout >= 0) or |
| 680 (self._interCharTimeout is not None and self._interCharTimeo
ut > 0)) and not buf: |
| 681 break # early abort on timeout |
| 682 return bytes(read) |
| 683 |
| 684 |
| 685 if __name__ == '__main__': |
| 686 s = Serial(0, |
| 687 baudrate=19200, # baud rate |
| 688 bytesize=EIGHTBITS, # number of data bits |
| 689 parity=PARITY_EVEN, # enable parity checking |
| 690 stopbits=STOPBITS_ONE, # number of stop bits |
| 691 timeout=3, # set a timeout value, None for waiting
forever |
| 692 xonxoff=0, # enable software flow control |
| 693 rtscts=0, # enable RTS/CTS flow control |
| 694 ) |
| 695 s.setRTS(1) |
| 696 s.setDTR(1) |
| 697 s.flushInput() |
| 698 s.flushOutput() |
| 699 s.write('hello') |
| 700 sys.stdout.write('%r\n' % s.read(5)) |
| 701 sys.stdout.write('%s\n' % s.inWaiting()) |
| 702 del s |
| 703 |
OLD | NEW |