Subversion Repositories Programming Utils

Rev

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
}