Rev 68 | Rev 76 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
7 | rm5248 | 1 | package com.rm5248.serial; |
2 | |||
30 | rm5248 | 3 | import java.io.Closeable; |
28 | rm5248 | 4 | import java.io.IOException; |
7 | rm5248 | 5 | import java.io.InputStream; |
6 | import java.io.OutputStream; |
||
7 | |||
42 | rm5248 | 8 | /** |
9 | * A SerialPort object represents a SerialPort object on the system. |
||
10 | * |
||
11 | * When creating a SerialPort object, you give the SerialPort the name of the port that you |
||
12 | * wish to open. |
||
13 | * |
||
68 | rm5248 | 14 | * When opening a SerialPort and setting values, an {@link IllegalArgumentException} may be thrown |
62 | rm5248 | 15 | * if any of the values are NULL. |
16 | * |
||
68 | rm5248 | 17 | * When getting and settings the properties of the SerialPort using one of the {@code getXXX() } |
18 | * or {@code setXXX() } methods, an IllegalStateException will be thrown if the port has been closed. |
||
62 | rm5248 | 19 | * |
42 | rm5248 | 20 | * @author rm5248 |
21 | * |
||
22 | */ |
||
30 | rm5248 | 23 | public class SerialPort implements Closeable { |
36 | rm5248 | 24 | |
11 | rm5248 | 25 | static{ |
26 | System.loadLibrary( "javaserial" ); |
||
27 | } |
||
7 | rm5248 | 28 | |
29 | /** |
||
30 | * Represents the BaudRate that the SerialPort uses. |
||
31 | */ |
||
32 | public enum BaudRate{ |
||
13 | rm5248 | 33 | /** Not available in Windows */ |
7 | rm5248 | 34 | B0, |
13 | rm5248 | 35 | /** Not available in Windows */ |
7 | rm5248 | 36 | B50, |
13 | rm5248 | 37 | /** Not available in Windows */ |
7 | rm5248 | 38 | B75, |
39 | B110, |
||
13 | rm5248 | 40 | /** Not available in Windows */ |
7 | rm5248 | 41 | B134, |
13 | rm5248 | 42 | /** Not available in Windows */ |
7 | rm5248 | 43 | B150, |
44 | B200, |
||
45 | B300, |
||
46 | B600, |
||
47 | B1200, |
||
13 | rm5248 | 48 | /** Not available in Windows */ |
7 | rm5248 | 49 | B1800, |
50 | B2400, |
||
51 | B4800, |
||
52 | B9600, |
||
53 | B38400, |
||
54 | B115200 |
||
55 | } |
||
11 | rm5248 | 56 | |
9 | rm5248 | 57 | /** |
58 | * Represents the number of bits that the serial port uses. |
||
59 | * Typically, this is 8-bit characters. |
||
60 | */ |
||
61 | public enum DataBits{ |
||
62 | DATABITS_5, |
||
63 | DATABITS_6, |
||
64 | DATABITS_7, |
||
65 | DATABITS_8 |
||
66 | } |
||
11 | rm5248 | 67 | |
9 | rm5248 | 68 | /** |
69 | * The number of stop bits for data. Typically this is 1. |
||
70 | */ |
||
71 | public enum StopBits{ |
||
72 | STOPBITS_1, |
||
73 | STOPBITS_2 |
||
74 | } |
||
11 | rm5248 | 75 | |
9 | rm5248 | 76 | /** |
77 | * The parity bit for the data. Typically None. |
||
78 | */ |
||
79 | public enum Parity{ |
||
80 | NONE, |
||
81 | EVEN, |
||
82 | ODD |
||
83 | } |
||
11 | rm5248 | 84 | |
9 | rm5248 | 85 | /** |
86 | * The Flow control scheme for the data, typically None. |
||
87 | */ |
||
88 | public enum FlowControl{ |
||
89 | NONE, |
||
90 | HARDWARE, |
||
91 | SOFTWARE |
||
92 | } |
||
7 | rm5248 | 93 | |
36 | rm5248 | 94 | private class SerialStateListener implements Runnable{ |
95 | |||
68 | rm5248 | 96 | private volatile boolean stop; |
36 | rm5248 | 97 | private SerialChangeListener listen; |
98 | |||
38 | rm5248 | 99 | SerialStateListener( SerialChangeListener listen ){ |
36 | rm5248 | 100 | stop = false; |
101 | this.listen = listen; |
||
102 | } |
||
103 | |||
104 | @Override |
||
105 | public void run() { |
||
106 | while( !stop ){ |
||
38 | rm5248 | 107 | synchronized( serialListenSync ){ |
108 | try { |
||
109 | serialListenSync.wait(); |
||
68 | rm5248 | 110 | if( stop ){ |
111 | break; |
||
112 | } |
||
38 | rm5248 | 113 | listen.serialStateChanged( state ); |
114 | } catch (Exception e) {} |
||
36 | rm5248 | 115 | } |
116 | } |
||
117 | } |
||
118 | |||
38 | rm5248 | 119 | void doStop(){ |
36 | rm5248 | 120 | stop = true; |
121 | } |
||
122 | } |
||
123 | |||
7 | rm5248 | 124 | /* The handle to our internal data structure which keeps track of the port settings. |
125 | * We need a special structure, as on windows we have a HANDLE type, which is void*, |
||
126 | * yet on Linux we have a file descriptor, which is an int. |
||
28 | rm5248 | 127 | * This is not just a pointer to memory, because if we're running on a 64-bit |
128 | * system, then we might have problems putting it in 32-bits. Better safe than sorry. |
||
7 | rm5248 | 129 | */ |
130 | private int handle; |
||
61 | rm5248 | 131 | /* The input stream that user code uses to read from the serial port. */ |
7 | rm5248 | 132 | private SerialInputStream inputStream; |
38 | rm5248 | 133 | /* The buffered serial input stream which filters out events for us. */ |
134 | private BufferedSerialInputStream bis; |
||
61 | rm5248 | 135 | /* The output stream that user code uses to write to the serial port. */ |
7 | rm5248 | 136 | private SerialOutputStream outputStream; |
9 | rm5248 | 137 | /* Make sure we don't close ourselves twice */ |
138 | private boolean closed; |
||
20 | rm5248 | 139 | /* The name of the port that's currently open */ |
140 | private String portName; |
||
36 | rm5248 | 141 | /* Cache of the last gotten serial line state */ |
38 | rm5248 | 142 | private volatile SerialLineState state; |
36 | rm5248 | 143 | /* Runs in the background to check for serial port events */ |
144 | private SerialStateListener serialListen; |
||
38 | rm5248 | 145 | /* Used for synchronizing serialListen */ |
146 | private Object serialListenSync; |
||
7 | rm5248 | 147 | |
148 | /** |
||
42 | rm5248 | 149 | * Open the specified port, 9600 baud, 8 data bits, 1 stop bit, no parity, no flow control |
7 | rm5248 | 150 | * |
42 | rm5248 | 151 | * @param portName The name of the port to open |
152 | * @throws NoSuchPortException If this port does not exist |
||
153 | * @throws NotASerialPortException If the specified port is not a serial port |
||
7 | rm5248 | 154 | */ |
9 | rm5248 | 155 | public SerialPort( String portName ) throws NoSuchPortException, NotASerialPortException { |
7 | rm5248 | 156 | this( portName, BaudRate.B9600 ); |
157 | } |
||
36 | rm5248 | 158 | |
11 | rm5248 | 159 | /** |
160 | * Open up a serial port, but allow the user to keep the current settings of the serial port. |
||
161 | * |
||
162 | * @param portName The port to open |
||
163 | * @param keepSettings If true, will simply open the serial port without setting anything. If false, this method |
||
68 | rm5248 | 164 | * acts the same as {@link #SerialPort(String) SerialPort( String portName ) } |
11 | rm5248 | 165 | * @throws NoSuchPortException If the port does not exist |
166 | * @throws NotASerialPortException If the port is not in fact a serial port |
||
167 | */ |
||
168 | public SerialPort( String portName, boolean keepSettings ) throws NoSuchPortException, NotASerialPortException{ |
||
62 | rm5248 | 169 | if( portName == null ){ |
170 | throw new IllegalArgumentException( "portName must not be null" ); |
||
171 | } |
||
172 | |||
11 | rm5248 | 173 | if( keepSettings ){ |
174 | this.handle = openPort( portName ); |
||
26 | rm5248 | 175 | this.portName = portName; |
176 | inputStream = new SerialInputStream( handle ); |
||
38 | rm5248 | 177 | bis = new BufferedSerialInputStream( inputStream, this ); |
26 | rm5248 | 178 | outputStream = new SerialOutputStream( handle ); |
179 | closed = false; |
||
36 | rm5248 | 180 | |
35 | rm5248 | 181 | SerialLineState s = new SerialLineState(); |
182 | int state = getSerialLineStateInternalNonblocking(); |
||
183 | // do some sort of bitwise operations here.... |
||
184 | if( ( state & 0x01 ) > 0 ){ |
||
185 | s.carrierDetect = true; |
||
65 | rm5248 | 186 | } |
187 | if( ( state & (0x01 << 1 ) ) > 0 ){ |
||
35 | rm5248 | 188 | s.clearToSend = true; |
65 | rm5248 | 189 | } |
190 | if( ( state & (0x01 << 2 ) ) > 0 ){ |
||
35 | rm5248 | 191 | s.dataSetReady = true; |
65 | rm5248 | 192 | } |
193 | if( ( state & (0x01 << 3 ) ) > 0 ){ |
||
35 | rm5248 | 194 | s.dataTerminalReady = true; |
65 | rm5248 | 195 | } |
196 | if( ( state & (0x01 << 4 ) ) > 0 ){ |
||
35 | rm5248 | 197 | s.requestToSend = true; |
65 | rm5248 | 198 | } |
199 | if( ( state & (0x01 << 5 ) ) > 0 ){ |
||
35 | rm5248 | 200 | s.ringIndicator = true; |
201 | } |
||
36 | rm5248 | 202 | |
35 | rm5248 | 203 | this.state = s; |
38 | rm5248 | 204 | serialListenSync = new Object(); |
11 | rm5248 | 205 | }else{ |
206 | this.handle = openPort( portName, 9600, 8, 1, 0, 0 ); |
||
207 | } |
||
38 | rm5248 | 208 | |
209 | new Thread( bis, "BufferedSerialReader" ).start(); |
||
11 | rm5248 | 210 | } |
7 | rm5248 | 211 | |
212 | /** |
||
42 | rm5248 | 213 | * Open the specified port, no flow control |
7 | rm5248 | 214 | * |
42 | rm5248 | 215 | * @param portName The name of the port to open |
61 | rm5248 | 216 | * @param rate The Baud Rate to open this port at |
42 | rm5248 | 217 | * @throws NoSuchPortException If this port does not exist |
218 | * @throws NotASerialPortException If the specified port is not a serial port |
||
7 | rm5248 | 219 | */ |
9 | rm5248 | 220 | public SerialPort( String portName, BaudRate rate )throws NoSuchPortException, NotASerialPortException { |
221 | this( portName, rate, DataBits.DATABITS_8 ); |
||
7 | rm5248 | 222 | } |
11 | rm5248 | 223 | |
42 | rm5248 | 224 | /** |
225 | * Open the specified port, no flow control |
||
9 | rm5248 | 226 | * |
42 | rm5248 | 227 | * @param portName The name of the port to open |
61 | rm5248 | 228 | * @param rate The Baud Rate to open this port at |
42 | rm5248 | 229 | * @param data The number of data bits |
230 | * @throws NoSuchPortException If this port does not exist |
||
231 | * @throws NotASerialPortException If the specified port is not a serial port |
||
9 | rm5248 | 232 | */ |
233 | public SerialPort( String portName, BaudRate rate, DataBits data ) throws NoSuchPortException, NotASerialPortException { |
||
234 | this( portName, rate, data, StopBits.STOPBITS_1 ); |
||
235 | } |
||
11 | rm5248 | 236 | |
42 | rm5248 | 237 | /** |
238 | * Open the specified port, no parity or flow control |
||
239 | * |
||
240 | * @param portName The name of the port to open |
||
61 | rm5248 | 241 | * @param rate The Baud Rate to open this port at |
42 | rm5248 | 242 | * @param data The number of data bits |
243 | * @param stop The number of stop bits |
||
244 | * @throws NoSuchPortException If this port does not exist |
||
245 | * @throws NotASerialPortException If the specified port is not a serial port |
||
246 | */ |
||
9 | rm5248 | 247 | public SerialPort( String portName, BaudRate rate, DataBits data, StopBits stop ) throws NoSuchPortException, NotASerialPortException { |
248 | this( portName, rate, data, stop, Parity.NONE ); |
||
249 | } |
||
11 | rm5248 | 250 | |
42 | rm5248 | 251 | /** |
252 | * Open the specified port, no flow control |
||
253 | * |
||
254 | * @param portName The name of the port to open |
||
61 | rm5248 | 255 | * @param rate The Baud Rate to open this port at |
42 | rm5248 | 256 | * @param data The number of data bits |
257 | * @param stop The number of stop bits |
||
258 | * @param parity The parity of the line |
||
259 | * @throws NoSuchPortException If this port does not exist |
||
260 | * @throws NotASerialPortException If the specified port is not a serial port |
||
261 | */ |
||
9 | rm5248 | 262 | public SerialPort( String portName, BaudRate rate, DataBits data, StopBits stop, Parity parity ) throws NoSuchPortException, NotASerialPortException { |
263 | this( portName, rate, data, stop, parity, FlowControl.NONE ); |
||
264 | } |
||
11 | rm5248 | 265 | |
42 | rm5248 | 266 | /** |
267 | * Open the specified port, defining all options |
||
268 | * |
||
269 | * @param portName The name of the port to open |
||
270 | * @param rate The Buad Rate to open this port at |
||
271 | * @param data The number of data bits |
||
272 | * @param stop The number of stop bits |
||
273 | * @param parity The parity of the line |
||
274 | * @param flow The flow control of the line |
||
275 | * @throws NoSuchPortException If this port does not exist |
||
276 | * @throws NotASerialPortException If the specified port is not a serial port |
||
277 | */ |
||
9 | rm5248 | 278 | public SerialPort( String portName, BaudRate rate, DataBits data, StopBits stop, Parity parity, FlowControl flow ) throws NoSuchPortException, NotASerialPortException { |
279 | int myRate = 0; |
||
280 | int myData = 0; |
||
281 | int myStop = 0; |
||
282 | int myParity = 0; |
||
283 | int myFlow = 0; |
||
35 | rm5248 | 284 | SerialLineState s; |
285 | int state; |
||
62 | rm5248 | 286 | |
287 | //Check for null values in our arguments |
||
288 | if( portName == null ){ |
||
289 | throw new IllegalArgumentException( "portName must not be null" ); |
||
290 | } |
||
291 | |||
292 | if( rate == null ){ |
||
293 | throw new IllegalArgumentException( "rate must not be null" ); |
||
294 | } |
||
295 | |||
296 | if( data == null ){ |
||
297 | throw new IllegalArgumentException( "data must not be null" ); |
||
298 | } |
||
299 | |||
300 | if( stop == null ){ |
||
301 | throw new IllegalArgumentException( "stop must not be null" ); |
||
302 | } |
||
303 | |||
304 | if( parity == null ){ |
||
305 | throw new IllegalArgumentException( "parity must not be null" ); |
||
306 | } |
||
307 | |||
308 | if( flow == null ){ |
||
309 | throw new IllegalArgumentException( "flow must not be null" ); |
||
310 | } |
||
36 | rm5248 | 311 | |
62 | rm5248 | 312 | //Okay, looks like we're good! |
20 | rm5248 | 313 | this.portName = portName; |
9 | rm5248 | 314 | closed = false; |
11 | rm5248 | 315 | |
9 | rm5248 | 316 | switch( rate ){ |
317 | case B0 : myRate = 0; break; |
||
318 | case B50 : myRate = 50; break; |
||
319 | case B75 : myRate = 75; break; |
||
320 | case B110 : myRate = 110; break; |
||
321 | case B134 : myRate = 134; break; |
||
322 | case B150 : myRate = 150; break; |
||
323 | case B200 : myRate = 200; break; |
||
324 | case B300 : myRate = 300; break; |
||
325 | case B600 : myRate = 600; break; |
||
326 | case B1200 : myRate = 1200; break; |
||
327 | case B1800 : myRate = 1800; break; |
||
328 | case B2400 : myRate = 2400; break; |
||
329 | case B4800 : myRate = 4800; break; |
||
330 | case B9600 : myRate = 9600; break; |
||
331 | case B38400 : myRate = 38400; break; |
||
332 | case B115200: myRate = 115200; break; |
||
333 | } |
||
11 | rm5248 | 334 | |
9 | rm5248 | 335 | switch( data ){ |
336 | case DATABITS_5: myData = 5; break; |
||
337 | case DATABITS_6: myData = 6; break; |
||
338 | case DATABITS_7: myData = 7; break; |
||
339 | case DATABITS_8: myData = 8; break; |
||
340 | } |
||
11 | rm5248 | 341 | |
9 | rm5248 | 342 | switch( stop ){ |
343 | case STOPBITS_1: myStop = 1; break; |
||
344 | case STOPBITS_2: myStop = 2; break; |
||
345 | } |
||
11 | rm5248 | 346 | |
9 | rm5248 | 347 | switch( parity ){ |
348 | case NONE: myParity = 0; break; |
||
349 | case ODD: myParity = 1; break; |
||
350 | case EVEN: myParity = 2; break; |
||
351 | } |
||
11 | rm5248 | 352 | |
9 | rm5248 | 353 | switch( flow ){ |
354 | case NONE: myFlow = 0; break; |
||
355 | case HARDWARE: myFlow = 1; break; |
||
356 | case SOFTWARE: myFlow = 2; break; |
||
357 | } |
||
11 | rm5248 | 358 | |
9 | rm5248 | 359 | handle = openPort(portName, myRate, myData, myStop, myParity, myFlow); |
360 | inputStream = new SerialInputStream( handle ); |
||
38 | rm5248 | 361 | bis = new BufferedSerialInputStream( inputStream, this ); |
9 | rm5248 | 362 | outputStream = new SerialOutputStream( handle ); |
36 | rm5248 | 363 | |
35 | rm5248 | 364 | s = new SerialLineState(); |
365 | state = getSerialLineStateInternalNonblocking(); |
||
366 | if( ( state & 0x01 ) > 0 ){ |
||
367 | s.carrierDetect = true; |
||
65 | rm5248 | 368 | } |
369 | if( ( state & (0x01 << 1 ) ) > 0 ){ |
||
35 | rm5248 | 370 | s.clearToSend = true; |
65 | rm5248 | 371 | } |
372 | if( ( state & (0x01 << 2 ) ) > 0 ){ |
||
35 | rm5248 | 373 | s.dataSetReady = true; |
65 | rm5248 | 374 | } |
375 | if( ( state & (0x01 << 3 ) ) > 0 ){ |
||
35 | rm5248 | 376 | s.dataTerminalReady = true; |
65 | rm5248 | 377 | } |
378 | if( ( state & (0x01 << 4 ) ) > 0 ){ |
||
35 | rm5248 | 379 | s.requestToSend = true; |
65 | rm5248 | 380 | } |
381 | if( ( state & (0x01 << 5 ) ) > 0 ){ |
||
35 | rm5248 | 382 | s.ringIndicator = true; |
383 | } |
||
36 | rm5248 | 384 | |
35 | rm5248 | 385 | this.state = s; |
38 | rm5248 | 386 | serialListenSync = new Object(); |
387 | new Thread( bis, "BufferedSerialReader" ).start(); |
||
9 | rm5248 | 388 | } |
7 | rm5248 | 389 | |
390 | /** |
||
391 | * Set the Baud Rate for this port. |
||
392 | * |
||
393 | * @param rate |
||
394 | */ |
||
395 | public void setBaudRate( BaudRate rate ){ |
||
9 | rm5248 | 396 | int myRate = 0; |
11 | rm5248 | 397 | |
9 | rm5248 | 398 | if( closed ){ |
399 | throw new IllegalStateException( "Cannot set the BaudRate once the port has been closed." ); |
||
400 | } |
||
62 | rm5248 | 401 | |
402 | if( rate == null ){ |
||
403 | throw new IllegalArgumentException( "rate must not be null" ); |
||
404 | } |
||
11 | rm5248 | 405 | |
7 | rm5248 | 406 | switch( rate ){ |
9 | rm5248 | 407 | case B0 : myRate = 0; break; |
408 | case B50 : myRate = 50; break; |
||
409 | case B75 : myRate = 75; break; |
||
410 | case B110 : myRate = 110; break; |
||
411 | case B134 : myRate = 134; break; |
||
412 | case B150 : myRate = 150; break; |
||
413 | case B200 : myRate = 200; break; |
||
414 | case B300 : myRate = 300; break; |
||
415 | case B600 : myRate = 600; break; |
||
416 | case B1200 : myRate = 1200; break; |
||
417 | case B1800 : myRate = 1800; break; |
||
418 | case B2400 : myRate = 2400; break; |
||
419 | case B4800 : myRate = 4800; break; |
||
420 | case B9600 : myRate = 9600; break; |
||
421 | case B38400 : myRate = 38400; break; |
||
422 | case B115200: myRate = 115200; break; |
||
7 | rm5248 | 423 | } |
11 | rm5248 | 424 | |
9 | rm5248 | 425 | setBaudRate( myRate ); |
7 | rm5248 | 426 | } |
427 | |||
428 | /** |
||
429 | * Get the input stream to be used to read from this SerialPort. |
||
430 | * |
||
431 | * @return The input stream. |
||
432 | */ |
||
433 | public InputStream getInputStream(){ |
||
9 | rm5248 | 434 | if( closed ){ |
435 | throw new IllegalStateException( "Cannot get the input stream once the port has been closed." ); |
||
436 | } |
||
11 | rm5248 | 437 | |
38 | rm5248 | 438 | return bis; |
7 | rm5248 | 439 | } |
440 | |||
441 | /** Get the output stream used to write data to this device. |
||
442 | * |
||
443 | * @return The output stream. |
||
444 | */ |
||
445 | public OutputStream getOutputStream(){ |
||
9 | rm5248 | 446 | if( closed ){ |
447 | throw new IllegalStateException( "Cannot get the output stream once the port has been closed." ); |
||
448 | } |
||
11 | rm5248 | 449 | |
7 | rm5248 | 450 | return outputStream; |
451 | } |
||
452 | |||
453 | /** |
||
454 | * Close the serial port, and all input streams |
||
455 | */ |
||
456 | public void close(){ |
||
9 | rm5248 | 457 | if( closed ) return; |
458 | closed = true; |
||
7 | rm5248 | 459 | doClose(); |
68 | rm5248 | 460 | serialListen.doStop(); |
461 | synchronized( serialListenSync ){ |
||
462 | serialListenSync.notify(); |
||
463 | } |
||
7 | rm5248 | 464 | } |
11 | rm5248 | 465 | |
9 | rm5248 | 466 | /** |
467 | * See if the port has been closed already. |
||
468 | * @return |
||
469 | */ |
||
470 | public boolean isClosed(){ |
||
471 | return closed; |
||
472 | } |
||
7 | rm5248 | 473 | |
474 | public void finalize(){ |
||
475 | close(); |
||
476 | } |
||
11 | rm5248 | 477 | |
9 | rm5248 | 478 | /** |
479 | * Set the stop bits of the serial port, after the port has been opened. |
||
480 | * |
||
481 | * @param stop |
||
482 | */ |
||
483 | public void setStopBits( StopBits stop ){ |
||
484 | int myStop = 0; |
||
11 | rm5248 | 485 | |
9 | rm5248 | 486 | if( closed ){ |
487 | throw new IllegalStateException( "Cannot set the StopBits once the port has been closed." ); |
||
488 | } |
||
62 | rm5248 | 489 | |
490 | if( stop == null ){ |
||
491 | throw new IllegalArgumentException( "stop must not be null" ); |
||
492 | } |
||
11 | rm5248 | 493 | |
9 | rm5248 | 494 | switch( stop ){ |
495 | case STOPBITS_1: myStop = 1; break; |
||
496 | case STOPBITS_2: myStop = 2; break; |
||
497 | } |
||
11 | rm5248 | 498 | |
9 | rm5248 | 499 | setStopBits( myStop ); |
500 | } |
||
11 | rm5248 | 501 | |
9 | rm5248 | 502 | /** |
503 | * Set the data bits size, after the port has been opened. |
||
504 | * |
||
505 | * @param data |
||
506 | */ |
||
507 | public void setDataSize( DataBits data ){ |
||
508 | int myData = 0; |
||
11 | rm5248 | 509 | |
9 | rm5248 | 510 | if( closed ){ |
511 | throw new IllegalStateException( "Cannot set the DataBits once the port has been closed." ); |
||
512 | } |
||
62 | rm5248 | 513 | |
514 | if( data == null ){ |
||
515 | throw new IllegalArgumentException( "data must not be null" ); |
||
516 | } |
||
11 | rm5248 | 517 | |
9 | rm5248 | 518 | switch( data ){ |
519 | case DATABITS_5: myData = 5; break; |
||
520 | case DATABITS_6: myData = 6; break; |
||
521 | case DATABITS_7: myData = 7; break; |
||
522 | case DATABITS_8: myData = 8; break; |
||
523 | } |
||
11 | rm5248 | 524 | |
9 | rm5248 | 525 | setCharSize( myData ); |
526 | } |
||
11 | rm5248 | 527 | |
10 | rm5248 | 528 | /** |
529 | * Set the parity of the serial port, after the port has been opened. |
||
530 | * |
||
531 | * @param parity |
||
532 | */ |
||
9 | rm5248 | 533 | public void setParity( Parity parity ){ |
534 | int myParity = 0; |
||
11 | rm5248 | 535 | |
9 | rm5248 | 536 | if( closed ){ |
10 | rm5248 | 537 | throw new IllegalStateException( "Cannot set the parity once the port has been closed." ); |
9 | rm5248 | 538 | } |
11 | rm5248 | 539 | |
62 | rm5248 | 540 | if( parity == null ){ |
541 | throw new IllegalArgumentException( "parity must not be null" ); |
||
542 | } |
||
543 | |||
9 | rm5248 | 544 | switch( parity ){ |
545 | case NONE: myParity = 0; break; |
||
546 | case ODD: myParity = 1; break; |
||
547 | case EVEN: myParity = 2; break; |
||
548 | } |
||
11 | rm5248 | 549 | |
9 | rm5248 | 550 | setParity( myParity ); |
551 | } |
||
11 | rm5248 | 552 | |
10 | rm5248 | 553 | /** |
554 | * Get the serial line state for the specified serial port. |
||
555 | * |
||
556 | * @return |
||
557 | */ |
||
36 | rm5248 | 558 | public SerialLineState getSerialLineState() throws IOException{ |
10 | rm5248 | 559 | if( closed ){ |
560 | throw new IllegalStateException( "Cannot get the serial line state once the port has been closed." ); |
||
561 | } |
||
11 | rm5248 | 562 | |
36 | rm5248 | 563 | int gotState = getSerialLineStateInternalNonblocking(); |
564 | |||
565 | SerialLineState s = new SerialLineState(); |
||
566 | // do some sort of bitwise operations here.... |
||
567 | if( ( gotState & 0x01 ) > 0 ){ |
||
568 | s.carrierDetect = true; |
||
63 | rm5248 | 569 | } |
570 | if( ( gotState & (0x01 << 1 ) ) > 0 ){ |
||
36 | rm5248 | 571 | s.clearToSend = true; |
63 | rm5248 | 572 | } |
573 | if( ( gotState & (0x01 << 2 ) ) > 0 ){ |
||
36 | rm5248 | 574 | s.dataSetReady = true; |
63 | rm5248 | 575 | } |
576 | if( ( gotState & (0x01 << 3 ) ) > 0 ){ |
||
36 | rm5248 | 577 | s.dataTerminalReady = true; |
63 | rm5248 | 578 | } |
579 | if( ( gotState & (0x01 << 4 ) ) > 0 ){ |
||
36 | rm5248 | 580 | s.requestToSend = true; |
63 | rm5248 | 581 | } |
582 | if( ( gotState & (0x01 << 5 ) ) > 0 ){ |
||
36 | rm5248 | 583 | s.ringIndicator = true; |
584 | } |
||
585 | |||
586 | return s; |
||
10 | rm5248 | 587 | } |
11 | rm5248 | 588 | |
10 | rm5248 | 589 | /** |
590 | * Set the serial line state to the parameters given. |
||
591 | * |
||
592 | * @param state |
||
593 | */ |
||
594 | public void setSerialLineState( SerialLineState state ){ |
||
62 | rm5248 | 595 | if( closed ){ |
596 | throw new IllegalStateException( "Cannot set the serial line state once the port has been closed." ); |
||
597 | } |
||
598 | |||
40 | rm5248 | 599 | setSerialLineStateInternal( state ); |
65 | rm5248 | 600 | |
601 | //Now, because Windows is weird, we need to post a serial changed event here. |
||
602 | //however, since we can only set DTR and RTS, only post an event if those are |
||
603 | //the things that changed |
||
604 | if( this.state.dataTerminalReady != state.dataTerminalReady || |
||
605 | this.state.requestToSend != state.requestToSend ){ |
||
606 | this.postSerialChangedEvent( state ); |
||
607 | } |
||
10 | rm5248 | 608 | } |
11 | rm5248 | 609 | |
10 | rm5248 | 610 | /** |
611 | * Get the baud rate of the serial port. |
||
612 | * |
||
613 | * @return |
||
614 | */ |
||
615 | public SerialPort.BaudRate getBaudRate(){ |
||
62 | rm5248 | 616 | int baudRate; |
617 | BaudRate toReturn; |
||
618 | |||
619 | if( closed ){ |
||
620 | throw new IllegalStateException( "Cannot get the baud rate once the port has been closed." ); |
||
621 | } |
||
622 | |||
623 | baudRate = getBaudRateInternal(); |
||
624 | toReturn = BaudRate.B0; |
||
11 | rm5248 | 625 | |
626 | switch( baudRate ){ |
||
627 | case 0 : toReturn = BaudRate.B0 ; break; |
||
628 | case 50 : toReturn = BaudRate.B50 ; break; |
||
629 | case 75 : toReturn = BaudRate.B75 ; break; |
||
630 | case 110 : toReturn = BaudRate.B110 ; break; |
||
631 | case 134 : toReturn = BaudRate.B134 ; break; |
||
632 | case 150 : toReturn = BaudRate.B150 ; break; |
||
633 | case 200 : toReturn = BaudRate.B200 ; break; |
||
634 | case 300 : toReturn = BaudRate.B300 ; break; |
||
635 | case 600 : toReturn = BaudRate.B600 ; break; |
||
636 | case 1200 : toReturn = BaudRate.B1200 ; break; |
||
637 | case 1800 : toReturn = BaudRate.B1800 ; break; |
||
638 | case 2400 : toReturn = BaudRate.B2400 ; break; |
||
639 | case 4800 : toReturn = BaudRate.B4800 ; break; |
||
640 | case 9600 : toReturn = BaudRate.B9600 ; break; |
||
641 | case 38400 : toReturn = BaudRate.B38400 ; break; |
||
642 | case 115200: toReturn = BaudRate.B115200; break; |
||
643 | } |
||
644 | |||
645 | return toReturn; |
||
10 | rm5248 | 646 | } |
11 | rm5248 | 647 | |
10 | rm5248 | 648 | /** |
649 | * Get the number of data bits. |
||
650 | * |
||
651 | * @return |
||
652 | */ |
||
653 | public SerialPort.DataBits getDataBits(){ |
||
62 | rm5248 | 654 | int dataBits; |
655 | DataBits bits; |
||
656 | |||
657 | if( closed ){ |
||
658 | throw new IllegalStateException( "Cannot get the data bits once the port has been closed." ); |
||
659 | } |
||
660 | |||
661 | dataBits = getCharSizeInternal(); |
||
662 | bits = DataBits.DATABITS_8; |
||
36 | rm5248 | 663 | |
11 | rm5248 | 664 | switch( dataBits ){ |
665 | case 8: bits = DataBits.DATABITS_8; break; |
||
666 | case 7: bits = DataBits.DATABITS_7; break; |
||
667 | case 6: bits = DataBits.DATABITS_6; break; |
||
668 | case 5: bits = DataBits.DATABITS_5; break; |
||
669 | } |
||
36 | rm5248 | 670 | |
11 | rm5248 | 671 | return bits; |
10 | rm5248 | 672 | } |
11 | rm5248 | 673 | |
10 | rm5248 | 674 | /** |
675 | * Get the number of stop bits. |
||
676 | * |
||
677 | * @return |
||
678 | */ |
||
679 | public SerialPort.StopBits getStopBits(){ |
||
62 | rm5248 | 680 | int stopBits; |
681 | StopBits bits; |
||
682 | |||
683 | if( closed ){ |
||
684 | throw new IllegalStateException( "Cannot get stop bits once the port has been closed." ); |
||
685 | } |
||
686 | |||
687 | stopBits = getStopBitsInternal(); |
||
688 | bits = StopBits.STOPBITS_1; |
||
36 | rm5248 | 689 | |
11 | rm5248 | 690 | switch( stopBits ){ |
691 | case 1: bits = StopBits.STOPBITS_1; break; |
||
692 | case 2: bits = StopBits.STOPBITS_2; break; |
||
693 | } |
||
36 | rm5248 | 694 | |
11 | rm5248 | 695 | return bits; |
10 | rm5248 | 696 | } |
11 | rm5248 | 697 | |
10 | rm5248 | 698 | /** |
699 | * Get the parity of the serial port. |
||
700 | * |
||
701 | * @return |
||
702 | */ |
||
703 | public SerialPort.Parity getParity(){ |
||
62 | rm5248 | 704 | int parity; |
705 | Parity par; |
||
706 | |||
707 | if( closed ){ |
||
708 | throw new IllegalStateException( "Cannot get the parity once the port has been closed." ); |
||
709 | } |
||
710 | |||
711 | parity = getParityInternal(); |
||
712 | par = Parity.NONE; |
||
36 | rm5248 | 713 | |
11 | rm5248 | 714 | switch( parity ){ |
715 | case 0: par = Parity.NONE; break; |
||
716 | case 1: par = Parity.ODD; break; |
||
717 | case 2: par = Parity.EVEN; break; |
||
718 | } |
||
36 | rm5248 | 719 | |
11 | rm5248 | 720 | return par; |
10 | rm5248 | 721 | } |
11 | rm5248 | 722 | |
10 | rm5248 | 723 | /** |
724 | * Get the flow control for the serial port. |
||
725 | * |
||
726 | * @return |
||
727 | */ |
||
728 | public SerialPort.FlowControl getFlowControl(){ |
||
62 | rm5248 | 729 | int flowControl; |
730 | FlowControl cont; |
||
731 | |||
732 | if( closed ){ |
||
733 | throw new IllegalStateException( "Cannot get the flow once the port has been closed." ); |
||
734 | } |
||
735 | |||
736 | flowControl = getFlowControlInternal(); |
||
737 | cont = FlowControl.NONE; |
||
36 | rm5248 | 738 | |
11 | rm5248 | 739 | switch( flowControl ){ |
740 | case 0: cont = FlowControl.NONE; break; |
||
741 | case 1: cont = FlowControl.HARDWARE; break; |
||
742 | case 2: cont = FlowControl.SOFTWARE; break; |
||
743 | } |
||
36 | rm5248 | 744 | |
11 | rm5248 | 745 | return cont; |
10 | rm5248 | 746 | } |
40 | rm5248 | 747 | |
42 | rm5248 | 748 | /** |
749 | * Set the flow control for the serial port |
||
750 | * |
||
751 | * @param flow |
||
752 | */ |
||
40 | rm5248 | 753 | public void setFlowControl( FlowControl flow ){ |
62 | rm5248 | 754 | if( closed ){ |
755 | throw new IllegalStateException( "Cannot set flow once the port has been closed." ); |
||
756 | } |
||
757 | |||
40 | rm5248 | 758 | switch( flow ){ |
759 | case HARDWARE: setFlowControl( 1 ); break; |
||
760 | case NONE: setFlowControl( 0 ); break; |
||
761 | case SOFTWARE: setFlowControl( 2 ); break; |
||
762 | } |
||
763 | } |
||
36 | rm5248 | 764 | |
38 | rm5248 | 765 | /** |
766 | * Set the listener which will get events when there is activity on the serial port. |
||
767 | * Note that this activity does NOT include receive and transmit events - this is |
||
768 | * changes on the lines of the serial port, such as RI, DSR, and DTR. |
||
769 | * |
||
62 | rm5248 | 770 | * If listen is null, will remove the listener. |
771 | * |
||
38 | rm5248 | 772 | * @param listen The listener which gets events |
773 | */ |
||
36 | rm5248 | 774 | public void setSerialChangeListener( SerialChangeListener listen ){ |
775 | if( serialListen != null ){ |
||
776 | serialListen.doStop(); |
||
777 | } |
||
28 | rm5248 | 778 | |
62 | rm5248 | 779 | if( listen != null ){ |
780 | serialListen = new SerialStateListener( listen ); |
||
781 | new Thread( serialListen, "SerialListen" ).start(); |
||
782 | } |
||
36 | rm5248 | 783 | |
28 | rm5248 | 784 | } |
36 | rm5248 | 785 | |
20 | rm5248 | 786 | public String toString(){ |
787 | return "Serial Port " + portName + ":" + getBaudRate(); |
||
788 | } |
||
36 | rm5248 | 789 | |
20 | rm5248 | 790 | /** |
791 | * Get the name of the serial port that this object represents. |
||
792 | * @return |
||
793 | */ |
||
794 | public String getPortName(){ |
||
795 | return portName; |
||
796 | } |
||
38 | rm5248 | 797 | |
798 | /** |
||
799 | * This method is called when the state of the serial lines is changed. |
||
800 | * |
||
801 | * @param newState |
||
802 | */ |
||
803 | void postSerialChangedEvent( SerialLineState newState ){ |
||
804 | if( !state.equals( newState ) ){ |
||
805 | state = newState; |
||
806 | |||
807 | synchronized( serialListenSync ){ |
||
808 | serialListenSync.notify(); |
||
809 | } |
||
810 | } |
||
811 | } |
||
7 | rm5248 | 812 | |
813 | /** |
||
814 | * Open the specified port, return an internal handle to the data structure for this port. |
||
815 | * |
||
816 | * @param portName |
||
817 | * @return |
||
818 | */ |
||
11 | rm5248 | 819 | private native int openPort( String portName, int baudRate, int dataBits, int stopBits, int parity, int flowControl ) throws NoSuchPortException, NotASerialPortException; |
7 | rm5248 | 820 | |
11 | rm5248 | 821 | /** |
822 | * Open the specified port, return an internal handle for the data of this port. |
||
823 | * This method DOES NOT set any of the serial port settings |
||
824 | * |
||
825 | * @param portName The port to open |
||
826 | * @return |
||
827 | */ |
||
828 | private native int openPort( String portName ) throws NoSuchPortException, NotASerialPortException; |
||
36 | rm5248 | 829 | |
11 | rm5248 | 830 | /** |
831 | * Close this port, release all native resources |
||
832 | */ |
||
833 | private native void doClose(); |
||
834 | |||
7 | rm5248 | 835 | /** |
9 | rm5248 | 836 | * Set the baud rate in the native code. |
7 | rm5248 | 837 | * |
838 | * @param baudRate |
||
839 | * @return |
||
840 | */ |
||
841 | private native boolean setBaudRate( int baudRate ); |
||
842 | |||
11 | rm5248 | 843 | private native int getBaudRateInternal(); |
7 | rm5248 | 844 | |
9 | rm5248 | 845 | /** |
846 | * Set the number of stop bits, once the port has been opened. |
||
847 | * |
||
848 | * @param stopBits |
||
849 | * @return |
||
850 | */ |
||
7 | rm5248 | 851 | private native boolean setStopBits( int stopBits ); |
852 | |||
11 | rm5248 | 853 | private native int getStopBitsInternal(); |
854 | |||
7 | rm5248 | 855 | /** |
11 | rm5248 | 856 | * Set the character size, once the port has been opened. |
857 | * This should probably be called 'setDataBits' |
||
9 | rm5248 | 858 | * |
859 | * @param charSize |
||
860 | * @return |
||
7 | rm5248 | 861 | */ |
9 | rm5248 | 862 | private native boolean setCharSize( int charSize ); |
11 | rm5248 | 863 | |
864 | private native int getCharSizeInternal(); |
||
865 | |||
9 | rm5248 | 866 | /** Set the parity once the port has been opened. |
867 | * |
||
11 | rm5248 | 868 | * @param parity 0 = None, 1 = Odd, 2 = Even |
9 | rm5248 | 869 | * @return |
870 | */ |
||
871 | private native boolean setParity( int parity ); |
||
7 | rm5248 | 872 | |
11 | rm5248 | 873 | private native int getParityInternal(); |
874 | |||
875 | /** Set the flow control once the port has been opened. |
||
876 | * |
||
877 | * |
||
878 | * @param flowControl 0 = None, 1 = hardware, 2 = software |
||
879 | * @return |
||
880 | */ |
||
881 | private native boolean setFlowControl( int flowControl ); |
||
882 | |||
883 | private native int getFlowControlInternal(); |
||
36 | rm5248 | 884 | |
28 | rm5248 | 885 | /** Get the serial line state, but don't block when getting it |
886 | * |
||
887 | * @return |
||
888 | */ |
||
889 | private native int getSerialLineStateInternalNonblocking(); |
||
40 | rm5248 | 890 | |
891 | /** |
||
892 | * Set the state of the serial line. |
||
893 | * @return |
||
894 | */ |
||
895 | private native int setSerialLineStateInternal( SerialLineState s ); |
||
61 | rm5248 | 896 | |
897 | // |
||
898 | // Static Methods |
||
899 | // |
||
900 | |||
901 | /** |
||
902 | * Get the major version of this library. For example, if this is version |
||
903 | * 0.2, this returns 0 |
||
904 | */ |
||
905 | public static int getMajorVersion(){ |
||
906 | return 0; |
||
907 | } |
||
908 | |||
909 | /** |
||
910 | * Get the minor version of this library. For example, if this is version |
||
911 | * 0.2, this returns 2. |
||
912 | */ |
||
913 | public static int getMinorVersion(){ |
||
68 | rm5248 | 914 | return 3; |
61 | rm5248 | 915 | } |
916 | |||
917 | /** |
||
918 | * Get the major version of the native code. This should match up with |
||
68 | rm5248 | 919 | * {@link #getMajorVersion() getMajorVersion()}, although this is not |
61 | rm5248 | 920 | * guaranteed. For example, if this is version 0.2, this returns 0 |
921 | */ |
||
922 | public static native int getMajorNativeVersion(); |
||
923 | |||
924 | /** |
||
925 | * Get the minor version of the native code. This should match up with |
||
68 | rm5248 | 926 | * {@link #getMinorVersion() getMinorVersion()}, although this is not |
61 | rm5248 | 927 | * guaranteed. For example, if this is version 0.2, this returns 2. |
928 | */ |
||
929 | public static native int getMinorNativeVersion(); |
||
68 | rm5248 | 930 | |
931 | /** |
||
69 | rm5248 | 932 | * <p> |
68 | rm5248 | 933 | * Get an array of all the serial ports on the system. For example, on |
934 | * Windows this will return {@code { "COM1", "COM3", .... } } depending on how |
||
935 | * many serial devices you have plugged in. On Linux, this returns |
||
936 | * {@code { "/dev/ttyS0", "/dev/ttyUSB0", "/dev/symlink", ... } } |
||
937 | * It will not resolve symlinks, such that if there is a symlink |
||
938 | * from {@code /dev/symlink } to {@code /dev/ttyUSB0 }, they will both show up. |
||
69 | rm5248 | 939 | * </p> |
940 | * <p> |
||
941 | * <b>NOTE:</b> this will only return ports that you have permissions to |
||
942 | * open. |
||
943 | * </p> |
||
68 | rm5248 | 944 | * |
945 | * @return |
||
946 | */ |
||
947 | public static native String[] getSerialPorts(); |
||
36 | rm5248 | 948 | |
7 | rm5248 | 949 | } |