blob: e5f2bbc4eb8dd4f5b24409db200d6f18f78fb0e9 [file] [log] [blame]
cliechtie8f75f92002-02-14 01:33:33 +00001#!jython
cliechti89b4af12002-02-12 23:24:41 +00002#
cliechti809b82e2008-06-22 22:45:04 +00003# Python Serial Port Extension for Win32, Linux, BSD, Jython
4# module for serial IO for Jython and JavaComm
5# see __init__.py
6#
Chris Liechti2cda7e62015-09-19 22:08:54 +02007# (C) 2002-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02008#
9# SPDX-License-Identifier: BSD-3-Clause
cliechti89b4af12002-02-12 23:24:41 +000010
cliechti39cfb7b2011-08-22 00:30:07 +000011from serial.serialutil import *
cliechti89b4af12002-02-12 23:24:41 +000012
Chris Liechti2cda7e62015-09-19 22:08:54 +020013
cliechti809b82e2008-06-22 22:45:04 +000014def my_import(name):
15 mod = __import__(name)
16 components = name.split('.')
17 for comp in components[1:]:
18 mod = getattr(mod, comp)
19 return mod
20
cliechti4a567a02009-07-27 22:09:31 +000021
cliechti809b82e2008-06-22 22:45:04 +000022def detect_java_comm(names):
23 """try given list of modules and return that imports"""
24 for name in names:
25 try:
26 mod = my_import(name)
27 mod.SerialPort
28 return mod
29 except (ImportError, AttributeError):
30 pass
31 raise ImportError("No Java Communications API implementation found")
32
cliechti4a567a02009-07-27 22:09:31 +000033
cliechti809b82e2008-06-22 22:45:04 +000034# Java Communications API implementations
35# http://mho.republika.pl/java/comm/
36
37comm = detect_java_comm([
Chris Liechti2cda7e62015-09-19 22:08:54 +020038 'javax.comm', # Sun/IBM
39 'gnu.io', # RXTX
cliechti809b82e2008-06-22 22:45:04 +000040])
cliechti89b4af12002-02-12 23:24:41 +000041
cliechti89b4af12002-02-12 23:24:41 +000042
43def device(portnumber):
cliechtid6bf52c2003-10-01 02:28:12 +000044 """Turn a port number into a device name"""
cliechti809b82e2008-06-22 22:45:04 +000045 enum = comm.CommPortIdentifier.getPortIdentifiers()
cliechti89b4af12002-02-12 23:24:41 +000046 ports = []
47 while enum.hasMoreElements():
48 el = enum.nextElement()
cliechti809b82e2008-06-22 22:45:04 +000049 if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL:
cliechti89b4af12002-02-12 23:24:41 +000050 ports.append(el)
cliechtid6bf52c2003-10-01 02:28:12 +000051 return ports[portnumber].getName()
cliechti89b4af12002-02-12 23:24:41 +000052
cliechtif81362e2009-07-25 03:44:33 +000053
Chris Liechtief6b7b42015-08-06 22:19:26 +020054class Serial(SerialBase):
cliechti7d448562014-08-03 21:57:45 +000055 """\
56 Serial port class, implemented with Java Communications API and
57 thus usable with jython and the appropriate java extension.
58 """
cliechti58b481c2009-02-16 20:42:32 +000059
cliechtid6bf52c2003-10-01 02:28:12 +000060 def open(self):
cliechti7d448562014-08-03 21:57:45 +000061 """\
62 Open port with current settings. This may throw a SerialException
63 if the port cannot be opened.
64 """
cliechtid6bf52c2003-10-01 02:28:12 +000065 if self._port is None:
66 raise SerialException("Port must be configured before it can be used.")
Chris Liechti2cda7e62015-09-19 22:08:54 +020067 if self.is_open:
cliechti8f69e702011-03-19 00:22:32 +000068 raise SerialException("Port is already open.")
cliechti4a567a02009-07-27 22:09:31 +000069 if type(self._port) == type(''): # strings are taken directly
cliechti809b82e2008-06-22 22:45:04 +000070 portId = comm.CommPortIdentifier.getPortIdentifier(self._port)
cliechti89b4af12002-02-12 23:24:41 +000071 else:
cliechti4a567a02009-07-27 22:09:31 +000072 portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj
cliechti4616bf12002-04-08 23:13:14 +000073 try:
74 self.sPort = portId.open("python serial module", 10)
Chris Liechti2cda7e62015-09-19 22:08:54 +020075 except Exception as msg:
cliechti4616bf12002-04-08 23:13:14 +000076 self.sPort = None
cliechtid6bf52c2003-10-01 02:28:12 +000077 raise SerialException("Could not open port: %s" % msg)
78 self._reconfigurePort()
79 self._instream = self.sPort.getInputStream()
80 self._outstream = self.sPort.getOutputStream()
Chris Liechti2cda7e62015-09-19 22:08:54 +020081 self.is_open = True
cliechti89b4af12002-02-12 23:24:41 +000082
cliechtid6bf52c2003-10-01 02:28:12 +000083 def _reconfigurePort(self):
cliechti4a567a02009-07-27 22:09:31 +000084 """Set communication parameters on opened port."""
cliechtid6bf52c2003-10-01 02:28:12 +000085 if not self.sPort:
86 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000087
cliechtid6bf52c2003-10-01 02:28:12 +000088 self.sPort.enableReceiveTimeout(30)
89 if self._bytesize == FIVEBITS:
cliechti809b82e2008-06-22 22:45:04 +000090 jdatabits = comm.SerialPort.DATABITS_5
cliechtid6bf52c2003-10-01 02:28:12 +000091 elif self._bytesize == SIXBITS:
cliechti809b82e2008-06-22 22:45:04 +000092 jdatabits = comm.SerialPort.DATABITS_6
cliechtid6bf52c2003-10-01 02:28:12 +000093 elif self._bytesize == SEVENBITS:
cliechti809b82e2008-06-22 22:45:04 +000094 jdatabits = comm.SerialPort.DATABITS_7
cliechtid6bf52c2003-10-01 02:28:12 +000095 elif self._bytesize == EIGHTBITS:
cliechti809b82e2008-06-22 22:45:04 +000096 jdatabits = comm.SerialPort.DATABITS_8
cliechti89b4af12002-02-12 23:24:41 +000097 else:
cliechtid6bf52c2003-10-01 02:28:12 +000098 raise ValueError("unsupported bytesize: %r" % self._bytesize)
cliechti58b481c2009-02-16 20:42:32 +000099
cliechtid6bf52c2003-10-01 02:28:12 +0000100 if self._stopbits == STOPBITS_ONE:
cliechti809b82e2008-06-22 22:45:04 +0000101 jstopbits = comm.SerialPort.STOPBITS_1
cliechtic5aed012014-08-01 02:34:22 +0000102 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
103 jstopbits = comm.SerialPort.STOPBITS_1_5
cliechtid6bf52c2003-10-01 02:28:12 +0000104 elif self._stopbits == STOPBITS_TWO:
cliechti809b82e2008-06-22 22:45:04 +0000105 jstopbits = comm.SerialPort.STOPBITS_2
cliechtid6bf52c2003-10-01 02:28:12 +0000106 else:
107 raise ValueError("unsupported number of stopbits: %r" % self._stopbits)
108
109 if self._parity == PARITY_NONE:
cliechti809b82e2008-06-22 22:45:04 +0000110 jparity = comm.SerialPort.PARITY_NONE
cliechtid6bf52c2003-10-01 02:28:12 +0000111 elif self._parity == PARITY_EVEN:
cliechti809b82e2008-06-22 22:45:04 +0000112 jparity = comm.SerialPort.PARITY_EVEN
cliechtid6bf52c2003-10-01 02:28:12 +0000113 elif self._parity == PARITY_ODD:
cliechti809b82e2008-06-22 22:45:04 +0000114 jparity = comm.SerialPort.PARITY_ODD
115 elif self._parity == PARITY_MARK:
116 jparity = comm.SerialPort.PARITY_MARK
117 elif self._parity == PARITY_SPACE:
118 jparity = comm.SerialPort.PARITY_SPACE
cliechtid6bf52c2003-10-01 02:28:12 +0000119 else:
120 raise ValueError("unsupported parity type: %r" % self._parity)
cliechti89b4af12002-02-12 23:24:41 +0000121
122 jflowin = jflowout = 0
cliechtid6bf52c2003-10-01 02:28:12 +0000123 if self._rtscts:
Chris Liechti2cda7e62015-09-19 22:08:54 +0200124 jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN
125 jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT
cliechtid6bf52c2003-10-01 02:28:12 +0000126 if self._xonxoff:
Chris Liechti2cda7e62015-09-19 22:08:54 +0200127 jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN
128 jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT
cliechti58b481c2009-02-16 20:42:32 +0000129
cliechti6670f732009-07-25 23:49:26 +0000130 self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity)
cliechti89b4af12002-02-12 23:24:41 +0000131 self.sPort.setFlowControlMode(jflowin | jflowout)
cliechti58b481c2009-02-16 20:42:32 +0000132
cliechtid6bf52c2003-10-01 02:28:12 +0000133 if self._timeout >= 0:
cliechtic5aed012014-08-01 02:34:22 +0000134 self.sPort.enableReceiveTimeout(int(self._timeout*1000))
cliechti89b4af12002-02-12 23:24:41 +0000135 else:
136 self.sPort.disableReceiveTimeout()
137
cliechti89b4af12002-02-12 23:24:41 +0000138 def close(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000139 """Close port"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200140 if self.is_open:
cliechtid6bf52c2003-10-01 02:28:12 +0000141 if self.sPort:
142 self._instream.close()
143 self._outstream.close()
144 self.sPort.close()
145 self.sPort = None
Chris Liechti2cda7e62015-09-19 22:08:54 +0200146 self.is_open = False
cliechti95c62212002-03-04 22:17:53 +0000147
cliechtid6bf52c2003-10-01 02:28:12 +0000148 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti95c62212002-03-04 22:17:53 +0000149
Chris Liechti2cda7e62015-09-19 22:08:54 +0200150 @property
151 def in_waiting(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000152 """Return the number of characters currently in the input buffer."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200153 if not self.sPort:
154 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000155 return self._instream.available()
cliechti89b4af12002-02-12 23:24:41 +0000156
cliechti4a567a02009-07-27 22:09:31 +0000157 def read(self, size=1):
cliechti7d448562014-08-03 21:57:45 +0000158 """\
159 Read size bytes from the serial port. If a timeout is set it may
160 return less characters as requested. With no timeout it will block
161 until the requested number of bytes is read.
162 """
Chris Liechti2cda7e62015-09-19 22:08:54 +0200163 if not self.sPort:
164 raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000165 read = bytearray()
cliechtia9e4e952002-05-26 01:20:22 +0000166 if size > 0:
167 while len(read) < size:
cliechtid6bf52c2003-10-01 02:28:12 +0000168 x = self._instream.read()
cliechtia9e4e952002-05-26 01:20:22 +0000169 if x == -1:
170 if self.timeout >= 0:
171 break
172 else:
cliechti4a567a02009-07-27 22:09:31 +0000173 read.append(x)
174 return bytes(read)
cliechti89b4af12002-02-12 23:24:41 +0000175
cliechti4a567a02009-07-27 22:09:31 +0000176 def write(self, data):
cliechtid6bf52c2003-10-01 02:28:12 +0000177 """Output the given string over the serial port."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200178 if not self.sPort:
179 raise portNotOpenError
cliechtiddd78132009-07-28 01:13:28 +0000180 if not isinstance(data, (bytes, bytearray)):
181 raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
cliechtid6bf52c2003-10-01 02:28:12 +0000182 self._outstream.write(data)
cliechtif81362e2009-07-25 03:44:33 +0000183 return len(data)
cliechtid6bf52c2003-10-01 02:28:12 +0000184
Chris Liechti2cda7e62015-09-19 22:08:54 +0200185 def reset_input_buffer(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000186 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200187 if not self.sPort:
188 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000189 self._instream.skip(self._instream.available())
cliechti89b4af12002-02-12 23:24:41 +0000190
Chris Liechti2cda7e62015-09-19 22:08:54 +0200191 def reset_output_buffer(self):
cliechti7d448562014-08-03 21:57:45 +0000192 """\
193 Clear output buffer, aborting the current output and
194 discarding all that is in the buffer.
195 """
Chris Liechti2cda7e62015-09-19 22:08:54 +0200196 if not self.sPort:
197 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000198 self._outstream.flush()
cliechti89b4af12002-02-12 23:24:41 +0000199
Chris Liechti2cda7e62015-09-19 22:08:54 +0200200 def send_break(self, duration=0.25):
cliechti997b63c2008-06-21 00:09:31 +0000201 """Send break condition. Timed, returns to idle state after given duration."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200202 if not self.sPort:
203 raise portNotOpenError
cliechtiaaa04602006-02-05 23:02:46 +0000204 self.sPort.sendBreak(duration*1000.0)
cliechti89b4af12002-02-12 23:24:41 +0000205
Chris Liechti2cda7e62015-09-19 22:08:54 +0200206 def _update_break_state(self):
cliechti997b63c2008-06-21 00:09:31 +0000207 """Set break: Controls TXD. When active, to transmitting is possible."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200208 if self.fd is None:
209 raise portNotOpenError
210 raise SerialException("The _update_break_state function is not implemented in java.")
cliechti997b63c2008-06-21 00:09:31 +0000211
Chris Liechti2cda7e62015-09-19 22:08:54 +0200212 def _update_rts_state(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000213 """Set terminal status line: Request To Send"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200214 if not self.sPort:
215 raise portNotOpenError
216 self.sPort.setRTS(self._rts_state)
cliechtif81362e2009-07-25 03:44:33 +0000217
Chris Liechti2cda7e62015-09-19 22:08:54 +0200218 def _update_dtr_state(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000219 """Set terminal status line: Data Terminal Ready"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200220 if not self.sPort:
221 raise portNotOpenError
222 self.sPort.setDTR(self._dtr_state)
cliechti89b4af12002-02-12 23:24:41 +0000223
Chris Liechti2cda7e62015-09-19 22:08:54 +0200224 @property
225 def cts(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000226 """Read terminal status line: Clear To Send"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200227 if not self.sPort:
228 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000229 self.sPort.isCTS()
230
Chris Liechti2cda7e62015-09-19 22:08:54 +0200231 @property
232 def dsr(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000233 """Read terminal status line: Data Set Ready"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200234 if not self.sPort:
235 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000236 self.sPort.isDSR()
237
Chris Liechti2cda7e62015-09-19 22:08:54 +0200238 @property
239 def ri(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000240 """Read terminal status line: Ring Indicator"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200241 if not self.sPort:
242 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000243 self.sPort.isRI()
244
Chris Liechti2cda7e62015-09-19 22:08:54 +0200245 @property
246 def cd(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000247 """Read terminal status line: Carrier Detect"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200248 if not self.sPort:
249 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000250 self.sPort.isCD()
251
252
cliechti89b4af12002-02-12 23:24:41 +0000253if __name__ == '__main__':
254 s = Serial(0,
cliechti4a567a02009-07-27 22:09:31 +0000255 baudrate=19200, # baudrate
256 bytesize=EIGHTBITS, # number of databits
257 parity=PARITY_EVEN, # enable parity checking
258 stopbits=STOPBITS_ONE, # number of stopbits
259 timeout=3, # set a timeout value, None for waiting forever
260 xonxoff=0, # enable software flow control
261 rtscts=0, # enable RTS/CTS flow control
262 )
cliechti89b4af12002-02-12 23:24:41 +0000263 s.setRTS(1)
264 s.setDTR(1)
Chris Liechti2cda7e62015-09-19 22:08:54 +0200265 s.reset_input_buffer()
266 s.reset_output_buffer()
cliechti89b4af12002-02-12 23:24:41 +0000267 s.write('hello')
cliechti7aaead32009-07-23 14:02:41 +0000268 sys.stdio.write('%r\n' % s.read(5))
Chris Liechti2cda7e62015-09-19 22:08:54 +0200269 sys.stdio.write('%s\n' % s.in_waiting())
cliechti89b4af12002-02-12 23:24:41 +0000270 del s
271