1#!jython 2# 3# Backend Jython with JavaComm 4# 5# This file is part of pySerial. https://github.com/pyserial/pyserial 6# (C) 2002-2015 Chris Liechti <cliechti@gmx.net> 7# 8# SPDX-License-Identifier: BSD-3-Clause 9 10from __future__ import absolute_import 11 12from serial.serialutil import * 13 14 15def 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 22 23def 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 34 35# Java Communications API implementations 36# http://mho.republika.pl/java/comm/ 37 38comm = detect_java_comm([ 39 'javax.comm', # Sun/IBM 40 'gnu.io', # RXTX 41]) 42 43 44def device(portnumber): 45 """Turn a port number into a device name""" 46 enum = comm.CommPortIdentifier.getPortIdentifiers() 47 ports = [] 48 while enum.hasMoreElements(): 49 el = enum.nextElement() 50 if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL: 51 ports.append(el) 52 return ports[portnumber].getName() 53 54 55class Serial(SerialBase): 56 """\ 57 Serial port class, implemented with Java Communications API and 58 thus usable with jython and the appropriate java extension. 59 """ 60 61 def open(self): 62 """\ 63 Open port with current settings. This may throw a SerialException 64 if the port cannot be opened. 65 """ 66 if self._port is None: 67 raise SerialException("Port must be configured before it can be used.") 68 if self.is_open: 69 raise SerialException("Port is already open.") 70 if type(self._port) == type(''): # strings are taken directly 71 portId = comm.CommPortIdentifier.getPortIdentifier(self._port) 72 else: 73 portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj 74 try: 75 self.sPort = portId.open("python serial module", 10) 76 except Exception as msg: 77 self.sPort = None 78 raise SerialException("Could not open port: %s" % msg) 79 self._reconfigurePort() 80 self._instream = self.sPort.getInputStream() 81 self._outstream = self.sPort.getOutputStream() 82 self.is_open = True 83 84 def _reconfigurePort(self): 85 """Set communication parameters on opened port.""" 86 if not self.sPort: 87 raise SerialException("Can only operate on a valid port handle") 88 89 self.sPort.enableReceiveTimeout(30) 90 if self._bytesize == FIVEBITS: 91 jdatabits = comm.SerialPort.DATABITS_5 92 elif self._bytesize == SIXBITS: 93 jdatabits = comm.SerialPort.DATABITS_6 94 elif self._bytesize == SEVENBITS: 95 jdatabits = comm.SerialPort.DATABITS_7 96 elif self._bytesize == EIGHTBITS: 97 jdatabits = comm.SerialPort.DATABITS_8 98 else: 99 raise ValueError("unsupported bytesize: %r" % self._bytesize) 100 101 if self._stopbits == STOPBITS_ONE: 102 jstopbits = comm.SerialPort.STOPBITS_1 103 elif self._stopbits == STOPBITS_ONE_POINT_FIVE: 104 jstopbits = comm.SerialPort.STOPBITS_1_5 105 elif self._stopbits == STOPBITS_TWO: 106 jstopbits = comm.SerialPort.STOPBITS_2 107 else: 108 raise ValueError("unsupported number of stopbits: %r" % self._stopbits) 109 110 if self._parity == PARITY_NONE: 111 jparity = comm.SerialPort.PARITY_NONE 112 elif self._parity == PARITY_EVEN: 113 jparity = comm.SerialPort.PARITY_EVEN 114 elif self._parity == PARITY_ODD: 115 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 120 else: 121 raise ValueError("unsupported parity type: %r" % self._parity) 122 123 jflowin = jflowout = 0 124 if self._rtscts: 125 jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN 126 jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT 127 if self._xonxoff: 128 jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN 129 jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT 130 131 self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity) 132 self.sPort.setFlowControlMode(jflowin | jflowout) 133 134 if self._timeout >= 0: 135 self.sPort.enableReceiveTimeout(int(self._timeout*1000)) 136 else: 137 self.sPort.disableReceiveTimeout() 138 139 def close(self): 140 """Close port""" 141 if self.is_open: 142 if self.sPort: 143 self._instream.close() 144 self._outstream.close() 145 self.sPort.close() 146 self.sPort = None 147 self.is_open = False 148 149 # - - - - - - - - - - - - - - - - - - - - - - - - 150 151 @property 152 def in_waiting(self): 153 """Return the number of characters currently in the input buffer.""" 154 if not self.sPort: 155 raise PortNotOpenError() 156 return self._instream.available() 157 158 def read(self, size=1): 159 """\ 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 """ 164 if not self.sPort: 165 raise PortNotOpenError() 166 read = bytearray() 167 if size > 0: 168 while len(read) < size: 169 x = self._instream.read() 170 if x == -1: 171 if self.timeout >= 0: 172 break 173 else: 174 read.append(x) 175 return bytes(read) 176 177 def write(self, data): 178 """Output the given string over the serial port.""" 179 if not self.sPort: 180 raise PortNotOpenError() 181 if not isinstance(data, (bytes, bytearray)): 182 raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) 183 self._outstream.write(data) 184 return len(data) 185 186 def reset_input_buffer(self): 187 """Clear input buffer, discarding all that is in the buffer.""" 188 if not self.sPort: 189 raise PortNotOpenError() 190 self._instream.skip(self._instream.available()) 191 192 def reset_output_buffer(self): 193 """\ 194 Clear output buffer, aborting the current output and 195 discarding all that is in the buffer. 196 """ 197 if not self.sPort: 198 raise PortNotOpenError() 199 self._outstream.flush() 200 201 def send_break(self, duration=0.25): 202 """Send break condition. Timed, returns to idle state after given duration.""" 203 if not self.sPort: 204 raise PortNotOpenError() 205 self.sPort.sendBreak(duration*1000.0) 206 207 def _update_break_state(self): 208 """Set break: Controls TXD. When active, to transmitting is possible.""" 209 if self.fd is None: 210 raise PortNotOpenError() 211 raise SerialException("The _update_break_state function is not implemented in java.") 212 213 def _update_rts_state(self): 214 """Set terminal status line: Request To Send""" 215 if not self.sPort: 216 raise PortNotOpenError() 217 self.sPort.setRTS(self._rts_state) 218 219 def _update_dtr_state(self): 220 """Set terminal status line: Data Terminal Ready""" 221 if not self.sPort: 222 raise PortNotOpenError() 223 self.sPort.setDTR(self._dtr_state) 224 225 @property 226 def cts(self): 227 """Read terminal status line: Clear To Send""" 228 if not self.sPort: 229 raise PortNotOpenError() 230 self.sPort.isCTS() 231 232 @property 233 def dsr(self): 234 """Read terminal status line: Data Set Ready""" 235 if not self.sPort: 236 raise PortNotOpenError() 237 self.sPort.isDSR() 238 239 @property 240 def ri(self): 241 """Read terminal status line: Ring Indicator""" 242 if not self.sPort: 243 raise PortNotOpenError() 244 self.sPort.isRI() 245 246 @property 247 def cd(self): 248 """Read terminal status line: Carrier Detect""" 249 if not self.sPort: 250 raise PortNotOpenError() 251 self.sPort.isCD() 252