blob: 9c920c53af34ec119385639fd6e7c409fbde283f [file] [log] [blame]
cliechtie8f75f92002-02-14 01:33:33 +00001#!jython
cliechti89b4af12002-02-12 23:24:41 +00002#
Chris Liechti3e02f702015-12-16 23:06:04 +01003# Backend Jython with JavaComm
cliechti809b82e2008-06-22 22:45:04 +00004#
Chris Liechti3e02f702015-12-16 23:06:04 +01005# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechti2cda7e62015-09-19 22:08:54 +02006# (C) 2002-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02007#
8# SPDX-License-Identifier: BSD-3-Clause
cliechti89b4af12002-02-12 23:24:41 +00009
Kurt McKee057387c2018-02-07 22:10:38 -060010from __future__ import absolute_import
11
cliechti39cfb7b2011-08-22 00:30:07 +000012from serial.serialutil import *
cliechti89b4af12002-02-12 23:24:41 +000013
Chris Liechti2cda7e62015-09-19 22:08:54 +020014
cliechti809b82e2008-06-22 22:45:04 +000015def my_import(name):
16 mod = __import__(name)
17 components = name.split('.')
18 for comp in components[1:]:
19 mod = getattr(mod, comp)
20 return mod
21
cliechti4a567a02009-07-27 22:09:31 +000022
cliechti809b82e2008-06-22 22:45:04 +000023def detect_java_comm(names):
24 """try given list of modules and return that imports"""
25 for name in names:
26 try:
27 mod = my_import(name)
28 mod.SerialPort
29 return mod
30 except (ImportError, AttributeError):
31 pass
32 raise ImportError("No Java Communications API implementation found")
33
cliechti4a567a02009-07-27 22:09:31 +000034
cliechti809b82e2008-06-22 22:45:04 +000035# Java Communications API implementations
36# http://mho.republika.pl/java/comm/
37
38comm = detect_java_comm([
Chris Liechti2cda7e62015-09-19 22:08:54 +020039 'javax.comm', # Sun/IBM
40 'gnu.io', # RXTX
cliechti809b82e2008-06-22 22:45:04 +000041])
cliechti89b4af12002-02-12 23:24:41 +000042
cliechti89b4af12002-02-12 23:24:41 +000043
44def device(portnumber):
cliechtid6bf52c2003-10-01 02:28:12 +000045 """Turn a port number into a device name"""
cliechti809b82e2008-06-22 22:45:04 +000046 enum = comm.CommPortIdentifier.getPortIdentifiers()
cliechti89b4af12002-02-12 23:24:41 +000047 ports = []
48 while enum.hasMoreElements():
49 el = enum.nextElement()
cliechti809b82e2008-06-22 22:45:04 +000050 if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL:
cliechti89b4af12002-02-12 23:24:41 +000051 ports.append(el)
cliechtid6bf52c2003-10-01 02:28:12 +000052 return ports[portnumber].getName()
cliechti89b4af12002-02-12 23:24:41 +000053
cliechtif81362e2009-07-25 03:44:33 +000054
Chris Liechtief6b7b42015-08-06 22:19:26 +020055class Serial(SerialBase):
cliechti7d448562014-08-03 21:57:45 +000056 """\
57 Serial port class, implemented with Java Communications API and
58 thus usable with jython and the appropriate java extension.
59 """
cliechti58b481c2009-02-16 20:42:32 +000060
cliechtid6bf52c2003-10-01 02:28:12 +000061 def open(self):
cliechti7d448562014-08-03 21:57:45 +000062 """\
63 Open port with current settings. This may throw a SerialException
64 if the port cannot be opened.
65 """
cliechtid6bf52c2003-10-01 02:28:12 +000066 if self._port is None:
67 raise SerialException("Port must be configured before it can be used.")
Chris Liechti2cda7e62015-09-19 22:08:54 +020068 if self.is_open:
cliechti8f69e702011-03-19 00:22:32 +000069 raise SerialException("Port is already open.")
cliechti4a567a02009-07-27 22:09:31 +000070 if type(self._port) == type(''): # strings are taken directly
cliechti809b82e2008-06-22 22:45:04 +000071 portId = comm.CommPortIdentifier.getPortIdentifier(self._port)
cliechti89b4af12002-02-12 23:24:41 +000072 else:
cliechti4a567a02009-07-27 22:09:31 +000073 portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj
cliechti4616bf12002-04-08 23:13:14 +000074 try:
75 self.sPort = portId.open("python serial module", 10)
Chris Liechti2cda7e62015-09-19 22:08:54 +020076 except Exception as msg:
cliechti4616bf12002-04-08 23:13:14 +000077 self.sPort = None
cliechtid6bf52c2003-10-01 02:28:12 +000078 raise SerialException("Could not open port: %s" % msg)
79 self._reconfigurePort()
80 self._instream = self.sPort.getInputStream()
81 self._outstream = self.sPort.getOutputStream()
Chris Liechti2cda7e62015-09-19 22:08:54 +020082 self.is_open = True
cliechti89b4af12002-02-12 23:24:41 +000083
cliechtid6bf52c2003-10-01 02:28:12 +000084 def _reconfigurePort(self):
cliechti4a567a02009-07-27 22:09:31 +000085 """Set communication parameters on opened port."""
cliechtid6bf52c2003-10-01 02:28:12 +000086 if not self.sPort:
87 raise SerialException("Can only operate on a valid port handle")
cliechti58b481c2009-02-16 20:42:32 +000088
cliechtid6bf52c2003-10-01 02:28:12 +000089 self.sPort.enableReceiveTimeout(30)
90 if self._bytesize == FIVEBITS:
cliechti809b82e2008-06-22 22:45:04 +000091 jdatabits = comm.SerialPort.DATABITS_5
cliechtid6bf52c2003-10-01 02:28:12 +000092 elif self._bytesize == SIXBITS:
cliechti809b82e2008-06-22 22:45:04 +000093 jdatabits = comm.SerialPort.DATABITS_6
cliechtid6bf52c2003-10-01 02:28:12 +000094 elif self._bytesize == SEVENBITS:
cliechti809b82e2008-06-22 22:45:04 +000095 jdatabits = comm.SerialPort.DATABITS_7
cliechtid6bf52c2003-10-01 02:28:12 +000096 elif self._bytesize == EIGHTBITS:
cliechti809b82e2008-06-22 22:45:04 +000097 jdatabits = comm.SerialPort.DATABITS_8
cliechti89b4af12002-02-12 23:24:41 +000098 else:
cliechtid6bf52c2003-10-01 02:28:12 +000099 raise ValueError("unsupported bytesize: %r" % self._bytesize)
cliechti58b481c2009-02-16 20:42:32 +0000100
cliechtid6bf52c2003-10-01 02:28:12 +0000101 if self._stopbits == STOPBITS_ONE:
cliechti809b82e2008-06-22 22:45:04 +0000102 jstopbits = comm.SerialPort.STOPBITS_1
cliechtic5aed012014-08-01 02:34:22 +0000103 elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
104 jstopbits = comm.SerialPort.STOPBITS_1_5
cliechtid6bf52c2003-10-01 02:28:12 +0000105 elif self._stopbits == STOPBITS_TWO:
cliechti809b82e2008-06-22 22:45:04 +0000106 jstopbits = comm.SerialPort.STOPBITS_2
cliechtid6bf52c2003-10-01 02:28:12 +0000107 else:
108 raise ValueError("unsupported number of stopbits: %r" % self._stopbits)
109
110 if self._parity == PARITY_NONE:
cliechti809b82e2008-06-22 22:45:04 +0000111 jparity = comm.SerialPort.PARITY_NONE
cliechtid6bf52c2003-10-01 02:28:12 +0000112 elif self._parity == PARITY_EVEN:
cliechti809b82e2008-06-22 22:45:04 +0000113 jparity = comm.SerialPort.PARITY_EVEN
cliechtid6bf52c2003-10-01 02:28:12 +0000114 elif self._parity == PARITY_ODD:
cliechti809b82e2008-06-22 22:45:04 +0000115 jparity = comm.SerialPort.PARITY_ODD
116 elif self._parity == PARITY_MARK:
117 jparity = comm.SerialPort.PARITY_MARK
118 elif self._parity == PARITY_SPACE:
119 jparity = comm.SerialPort.PARITY_SPACE
cliechtid6bf52c2003-10-01 02:28:12 +0000120 else:
121 raise ValueError("unsupported parity type: %r" % self._parity)
cliechti89b4af12002-02-12 23:24:41 +0000122
123 jflowin = jflowout = 0
cliechtid6bf52c2003-10-01 02:28:12 +0000124 if self._rtscts:
Chris Liechti2cda7e62015-09-19 22:08:54 +0200125 jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN
126 jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT
cliechtid6bf52c2003-10-01 02:28:12 +0000127 if self._xonxoff:
Chris Liechti2cda7e62015-09-19 22:08:54 +0200128 jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN
129 jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT
cliechti58b481c2009-02-16 20:42:32 +0000130
cliechti6670f732009-07-25 23:49:26 +0000131 self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity)
cliechti89b4af12002-02-12 23:24:41 +0000132 self.sPort.setFlowControlMode(jflowin | jflowout)
cliechti58b481c2009-02-16 20:42:32 +0000133
cliechtid6bf52c2003-10-01 02:28:12 +0000134 if self._timeout >= 0:
cliechtic5aed012014-08-01 02:34:22 +0000135 self.sPort.enableReceiveTimeout(int(self._timeout*1000))
cliechti89b4af12002-02-12 23:24:41 +0000136 else:
137 self.sPort.disableReceiveTimeout()
138
cliechti89b4af12002-02-12 23:24:41 +0000139 def close(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000140 """Close port"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200141 if self.is_open:
cliechtid6bf52c2003-10-01 02:28:12 +0000142 if self.sPort:
143 self._instream.close()
144 self._outstream.close()
145 self.sPort.close()
146 self.sPort = None
Chris Liechti2cda7e62015-09-19 22:08:54 +0200147 self.is_open = False
cliechti95c62212002-03-04 22:17:53 +0000148
cliechtid6bf52c2003-10-01 02:28:12 +0000149 # - - - - - - - - - - - - - - - - - - - - - - - -
cliechti95c62212002-03-04 22:17:53 +0000150
Chris Liechti2cda7e62015-09-19 22:08:54 +0200151 @property
152 def in_waiting(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000153 """Return the number of characters currently in the input buffer."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200154 if not self.sPort:
155 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000156 return self._instream.available()
cliechti89b4af12002-02-12 23:24:41 +0000157
cliechti4a567a02009-07-27 22:09:31 +0000158 def read(self, size=1):
cliechti7d448562014-08-03 21:57:45 +0000159 """\
160 Read size bytes from the serial port. If a timeout is set it may
161 return less characters as requested. With no timeout it will block
162 until the requested number of bytes is read.
163 """
Chris Liechti2cda7e62015-09-19 22:08:54 +0200164 if not self.sPort:
165 raise portNotOpenError
cliechti4a567a02009-07-27 22:09:31 +0000166 read = bytearray()
cliechtia9e4e952002-05-26 01:20:22 +0000167 if size > 0:
168 while len(read) < size:
cliechtid6bf52c2003-10-01 02:28:12 +0000169 x = self._instream.read()
cliechtia9e4e952002-05-26 01:20:22 +0000170 if x == -1:
171 if self.timeout >= 0:
172 break
173 else:
cliechti4a567a02009-07-27 22:09:31 +0000174 read.append(x)
175 return bytes(read)
cliechti89b4af12002-02-12 23:24:41 +0000176
cliechti4a567a02009-07-27 22:09:31 +0000177 def write(self, data):
cliechtid6bf52c2003-10-01 02:28:12 +0000178 """Output the given string over the serial port."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200179 if not self.sPort:
180 raise portNotOpenError
cliechtiddd78132009-07-28 01:13:28 +0000181 if not isinstance(data, (bytes, bytearray)):
182 raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
cliechtid6bf52c2003-10-01 02:28:12 +0000183 self._outstream.write(data)
cliechtif81362e2009-07-25 03:44:33 +0000184 return len(data)
cliechtid6bf52c2003-10-01 02:28:12 +0000185
Chris Liechti2cda7e62015-09-19 22:08:54 +0200186 def reset_input_buffer(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000187 """Clear input buffer, discarding all that is in the buffer."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200188 if not self.sPort:
189 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000190 self._instream.skip(self._instream.available())
cliechti89b4af12002-02-12 23:24:41 +0000191
Chris Liechti2cda7e62015-09-19 22:08:54 +0200192 def reset_output_buffer(self):
cliechti7d448562014-08-03 21:57:45 +0000193 """\
194 Clear output buffer, aborting the current output and
195 discarding all that is in the buffer.
196 """
Chris Liechti2cda7e62015-09-19 22:08:54 +0200197 if not self.sPort:
198 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000199 self._outstream.flush()
cliechti89b4af12002-02-12 23:24:41 +0000200
Chris Liechti2cda7e62015-09-19 22:08:54 +0200201 def send_break(self, duration=0.25):
cliechti997b63c2008-06-21 00:09:31 +0000202 """Send break condition. Timed, returns to idle state after given duration."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200203 if not self.sPort:
204 raise portNotOpenError
cliechtiaaa04602006-02-05 23:02:46 +0000205 self.sPort.sendBreak(duration*1000.0)
cliechti89b4af12002-02-12 23:24:41 +0000206
Chris Liechti2cda7e62015-09-19 22:08:54 +0200207 def _update_break_state(self):
cliechti997b63c2008-06-21 00:09:31 +0000208 """Set break: Controls TXD. When active, to transmitting is possible."""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200209 if self.fd is None:
210 raise portNotOpenError
211 raise SerialException("The _update_break_state function is not implemented in java.")
cliechti997b63c2008-06-21 00:09:31 +0000212
Chris Liechti2cda7e62015-09-19 22:08:54 +0200213 def _update_rts_state(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000214 """Set terminal status line: Request To Send"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200215 if not self.sPort:
216 raise portNotOpenError
217 self.sPort.setRTS(self._rts_state)
cliechtif81362e2009-07-25 03:44:33 +0000218
Chris Liechti2cda7e62015-09-19 22:08:54 +0200219 def _update_dtr_state(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000220 """Set terminal status line: Data Terminal Ready"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200221 if not self.sPort:
222 raise portNotOpenError
223 self.sPort.setDTR(self._dtr_state)
cliechti89b4af12002-02-12 23:24:41 +0000224
Chris Liechti2cda7e62015-09-19 22:08:54 +0200225 @property
226 def cts(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000227 """Read terminal status line: Clear To Send"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200228 if not self.sPort:
229 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000230 self.sPort.isCTS()
231
Chris Liechti2cda7e62015-09-19 22:08:54 +0200232 @property
233 def dsr(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000234 """Read terminal status line: Data Set Ready"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200235 if not self.sPort:
236 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000237 self.sPort.isDSR()
238
Chris Liechti2cda7e62015-09-19 22:08:54 +0200239 @property
240 def ri(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000241 """Read terminal status line: Ring Indicator"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200242 if not self.sPort:
243 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000244 self.sPort.isRI()
245
Chris Liechti2cda7e62015-09-19 22:08:54 +0200246 @property
247 def cd(self):
cliechtid6bf52c2003-10-01 02:28:12 +0000248 """Read terminal status line: Carrier Detect"""
Chris Liechti2cda7e62015-09-19 22:08:54 +0200249 if not self.sPort:
250 raise portNotOpenError
cliechtid6bf52c2003-10-01 02:28:12 +0000251 self.sPort.isCD()