pytty

view src/__init__.py @ 30:873320419f15

Added baudrate to __str__ and __repr__ output
author Arc Riley <arcriley@gmail.com>
date Tue, 10 Jul 2012 03:53:06 -0400
parents 10bc49064475
children 34b161a8e076
line source
1 # -*- coding: utf-8 -*-
3 '''Python serial access package
5 This package provides easy access to TTY devices from Python.
6 '''
8 __credits__ = '''Copyright (C) 2010,2011,2012 Arc Riley
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published
12 by the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with this program; if not, see http://www.gnu.org/licenses
22 '''
24 __author__ = '\n'.join((
25 'Arc Riley <arcriley@gmail.com>',
26 'Chris Koepke',
27 ))
29 __version__ = '0.3'
31 import io
33 class TTY (io.BufferedRWPair) :
34 '''TTY io class
36 This is a subclass of io.BufferedRWPair from the Python standard library
37 which opens a tty device, sets nonblock mode on the device, and allows the
38 user to change baud rate, flow control, and other settings often available
39 to tty devices.
41 >>> import pty
42 >>> ptys = pty.openpty() # create two connected ptys for testing
43 >>> master = pytty.TTY(ptys[0])
44 >>> slave = pytty.TTY(ptys[1])
45 >>> slave.write('Greetings, Master.'.encode()) == 18
46 True
47 >>> slave.flush()
48 >>> print(master.read().decode())
49 Greetings, Master.
50 '''
52 # This is intended to be overridden by some subclasses
53 _iobase = io.FileIO
55 def __init__ (self, name) :
56 from fcntl import fcntl, F_SETFL, F_GETFL
57 from os import O_NONBLOCK
59 reader = self._iobase(name, 'r')
61 # ensure this is actually a tty device
62 if not reader.isatty() :
63 raise IOError('%s is not a tty device' % name)
65 # set non-blocking mode on the reader
66 self._fdo = reader.fileno()
67 fcntl(self._fdo, F_SETFL, (fcntl(self._fdo, F_GETFL) | O_NONBLOCK))
69 # open a separate writer device
70 writer = self._iobase(name, 'w')
72 # set non-blocking mode on the reader
73 self._fdi = reader.fileno()
74 fcntl(self._fdi, F_SETFL, (fcntl(self._fdi, F_GETFL) | O_NONBLOCK))
76 # initialize self with BufferedRWPair
77 super(TTY, self).__init__(reader, writer)
79 def __repr__(self) :
80 return '<pytty.TTY (%s)>' % str(self)
82 def __str__(self) :
83 return '%s %i%s%i' % (self.baud, self.bits, self.parity, self.stops)
85 @property
86 def baud (self) :
87 '''Baud rate
89 Value must be supported by the tty device and in this list::
91 [0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
92 9600, 19200, 38400, 57600, 115200, 230400, 460800]
93 '''
94 import termios
95 return {
96 termios.B0 : 0, termios.B50 : 50,
97 termios.B75 : 75, termios.B110 : 110,
98 termios.B134 : 134, termios.B150 : 150,
99 termios.B200 : 200, termios.B300 : 300,
100 termios.B600 : 600, termios.B1200 : 1200,
101 termios.B1800 : 1800, termios.B2400 : 2400,
102 termios.B4800 : 4800, termios.B9600 : 9600,
103 termios.B19200 : 19200, termios.B38400 : 38400,
104 termios.B57600 : 57600, termios.B115200 : 115200,
105 termios.B230400 : 230400, termios.B460800 : 460800,
106 }[termios.tcgetattr(self._fdi)[4]]
108 @baud.setter
109 def baud (self, value) :
110 import termios
111 try :
112 tv = {
113 0 : termios.B0, 50 : termios.B50,
114 75 : termios.B75, 110 : termios.B110,
115 134 : termios.B134, 150 : termios.B150,
116 200 : termios.B200, 300 : termios.B300,
117 600 : termios.B600, 1200 : termios.B1200,
118 1800 : termios.B1800, 2400 : termios.B2400,
119 4800 : termios.B4800, 9600 : termios.B9600,
120 19200 : termios.B19200, 38400 : termios.B38400,
121 57600 : termios.B57600, 115200 : termios.B115200,
122 230400 : termios.B230400, 460800 : termios.B460800,
123 }[value]
124 except KeyError :
125 raise IOError('Baud rate not supported by PyTTY.')
126 tci = termios.tcgetattr(self._fdi)
127 tco = termios.tcgetattr(self._fdo)
128 tci[4], tci[5], tco[4], tco[5] = (tv,)*4
129 termios.tcsetattr(self._fdi, termios.TCSANOW, tci)
130 termios.tcsetattr(self._fdo, termios.TCSANOW, tco)
132 @property
133 def bits (self) :
134 '''Number of bits per byte
136 This property determines how many bits are in a byte, between 5 and 8.
137 '''
138 import termios
139 cflag = termios.tcgetattr(self._fdi)[2]
140 return ((cflag & termios.CS8 and 8) or (cflag & termios.CS7 and 7) or
141 (cflag & termios.CS6 and 6) or (cflag & termios.CS5 and 5))
143 @bits.setter
144 def bits (self, value) :
145 import termios
146 if value < 5 or value > 8 :
147 raise IOError('Byte size must be between 5 and 8 bits.')
148 cs = (termios.CS5, termios.CS6, termios.CS7, termios.CS8)[value-5]
149 for fd in (self._fdi, self._fdo) :
150 tc = termios.tcgetattr(fd)
151 tc[2] &= cs
152 termios.tcsetattr(fd, termios.TCSANOW, tc)
154 @property
155 def parity (self) :
156 '''Parity bit
158 This may be set to 'N' (none), 'E' (even), or 'O' (odd).
159 '''
160 import termios
161 cflag = termios.tcgetattr(self._fdi)[2]
162 return ((('N', 'N'), ('E', 'O'))
163 [cflag & termios.PARENB and 1][cflag & termios.PARODD and 1])
165 @parity.setter
166 def parity (self, value) :
167 import termios
168 for fd in (self._fdi, self._fdo) :
169 tc = termios.tcgetattr(fd)
170 if value in 'Nn' :
171 tc[2] &= ~termios.PARENB
172 else :
173 tc[2] |= termios.PARENB
174 if value in 'Ee' :
175 tc[2] &= ~termios.PARODD
176 elif value in 'Oo' :
177 tc[2] |= termios.PARODD
178 else :
179 raise IOError("Parity must be 'N', 'E', or 'O'.")
180 termios.tcsetattr(fd, termios.TCSANOW, tc)
182 @property
183 def stops (self) :
184 '''Number of stop bits
186 How many stop bits follow a byte, either 1 or 2.
187 '''
188 import termios
189 cflag = termios.tcgetattr(self._fdi)[2]
190 return (1, 2)[termios.tcgetattr(self._fdi)[2] & termios.CSTOPB and 1]
192 @stops.setter
193 def stops (self, value) :
194 import termios
195 for fd in (self._fdi, self._fdo) :
196 tc = termios.tcgetattr(fd)
197 if value == 1 :
198 tc[2] &= ~termios.CSTOPB
199 elif value == 2 :
200 tc[2] &= termios.CSTOPB
201 else :
202 raise IOError('Stop bits must be either 1 or 2.')
203 termios.tcsetattr(fd, termios.TCSANOW, tc)
205 # Clean up package namespace
206 del(io)