Subversion Repositories Programming Utils

Rev

Rev 96 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13 rm5248 1
#ifdef _WIN32
2
        #include <windows.h>
3
 
55 rm5248 4
        /* Make inline functions work */
5
        #define inline __inline
6
 
13 rm5248 7
        #define SPEED_SWITCH(SPD,io) case SPD: io.BaudRate = CBR_##SPD; break;
23 rm5248 8
        #define GET_SPEED_SWITCH(SPD,io) case CBR_##SPD: return SPD;
13 rm5248 9
 
10
        #define GET_SERIAL_PORT_STRUCT( port, io_name ) DCB io_name = {0};\
11
                                                                                                io_name.DCBlength = sizeof( io_name ); \
12
                                                                                                if (!GetCommState( port, &io_name ) ) { \
27 rm5248 13
                                                                                                printf("bad get comm\n");\
13 rm5248 14
                                                                                                        return -1;\
15
                                                                                                }
16
        #define SET_SERIAL_PORT_STRUCT( port, io_name )         if( !SetCommState( port, &io_name ) ){\
27 rm5248 17
        printf("bad set comm\n");\
13 rm5248 18
                                                                                                                        return 0;\
19
                                                                                                                }
68 rm5248 20
 
21
        #define close(handle) CloseHandle(handle)
8 rm5248 22
#else
23
        #include <termios.h>
24
        #include <unistd.h>
25
        #include <fcntl.h>
69 rm5248 26
        #include <unistd.h>
27
        #include <dirent.h>
77 rm5248 28
        #include <pthread.h>
80 rm5248 29
        #include <sys/ioctl.h>
30
        #include <errno.h>
14 rm5248 31
 
80 rm5248 32
        #ifndef ENOMEDIUM
33
        #define ENOMEDIUM ENODEV
34
        #endif
35
 
14 rm5248 36
        #ifdef CRTSCTS
37
                #define HW_FLOW CRTSCTS
38
        #elif CNEW_RTSCTS
39
                #define HW_FLOW CNEW_RTSCTS
40
        #endif
8 rm5248 41
 
20 rm5248 42
        #define SPEED_SWITCH(SPD,io) case SPD: cfsetospeed( &io, B##SPD ); cfsetispeed( &io, B##SPD ); break;
43
        #define GET_SPEED_SWITCH(SPD,io) case B##SPD: return SPD;
13 rm5248 44
 
45
 
46
        #define GET_SERIAL_PORT_STRUCT( port, io_name ) struct termios io_name; \
47
                                                                                                        if( tcgetattr( port, &io_name ) < 0 ){ \
48
                                                                                                                return -1; \
49
                                                                                                        }
50
        #define SET_SERIAL_PORT_STRUCT( port, io_name )         if( tcsetattr( port, TCSANOW, &io_name ) < 0 ){\
57 rm5248 51
                                                                                                                        return -1;\
13 rm5248 52
                                                                                                                }
8 rm5248 53
#endif
13 rm5248 54
 
8 rm5248 55
#include <stdlib.h>
56
#include <errno.h>
57
#include <string.h>
58
 
59
//
60
// Local Includes
61
//
62
#include "com_rm5248_serial_SerialPort.h"
18 rm5248 63
#include "com_rm5248_serial_SerialInputStream.h"
64
#include "com_rm5248_serial_SerialOutputStream.h"
96 rm5248 65
#include "com_rm5248_serial_SimpleSerialInputStream.h"
8 rm5248 66
 
67
//
68
// Struct Definitions
69
//
70
struct port_descriptor{
13 rm5248 71
#ifdef _WIN32
8 rm5248 72
        HANDLE port;
73
#else
74
        int port;
77 rm5248 75
        /* There appears to be a case where we can free() the port_descriptor
76
         * after the select() call in SerialInputStream_readByte().
77
         * This means that we segfault on the FD_SET() call.
78
         * This mutex will keep us alive until we have exited the
79
         * readByte() call.
80
         */
81
        pthread_mutex_t in_use;
8 rm5248 82
#endif
83
};
84
 
85
//
86
// Local Variables
87
//
77 rm5248 88
static struct port_descriptor** port_list = NULL;
89
static int port_list_size;
8 rm5248 90
 
65 rm5248 91
#ifdef _WIN32
92
//Unfortunately, Windows does not let us get the state of the DTR/RTS lines.
93
//So, we need to keep track of that manually.  
94
int winDTR = 0;
95
int winRTS = 0;
96
#endif
97
 
8 rm5248 98
//
99
// Helper Methods
100
//
55 rm5248 101
static inline jint get_handle(JNIEnv * env, jobject obj){
8 rm5248 102
        jfieldID fid;
103
        jint array_pos;
104
        jclass cls = (*env)->GetObjectClass( env, obj );
105
 
106
        fid = (*env)->GetFieldID( env, cls, "handle", "I" );
107
        if( fid == 0 ){
108
                return -1;
109
        }
110
 
18 rm5248 111
        array_pos = (*env)->GetIntField( env, obj, fid );
8 rm5248 112
 
113
        return array_pos;
114
}
115
 
55 rm5248 116
static inline jboolean get_bool( JNIEnv* env, jobject obj, const char* name ){
40 rm5248 117
        jfieldID fid;
118
        jboolean boolVal;
119
        jclass cls = (*env)->GetObjectClass( env, obj );
120
 
121
        fid = (*env)->GetFieldID( env, cls, name, "Z" );
122
        if( fid == 0 ){
123
                return 0; //not really sure what error to set here...
124
        }
125
 
126
        boolVal = (*env)->GetBooleanField( env, obj, fid );
127
 
128
        return boolVal;
129
}
130
 
55 rm5248 131
static inline int set_baud_rate( struct port_descriptor* desc, int baud_rate ){
13 rm5248 132
        GET_SERIAL_PORT_STRUCT( desc->port, newio );
11 rm5248 133
 
134
        switch( baud_rate ){
13 rm5248 135
#ifndef _WIN32
136
/* Note that Windows only supports speeds of 110 and above */
11 rm5248 137
                SPEED_SWITCH(0,newio);
138
                SPEED_SWITCH(50,newio);
139
                SPEED_SWITCH(75,newio);
13 rm5248 140
#endif
11 rm5248 141
                SPEED_SWITCH(110,newio);
13 rm5248 142
#ifndef _WIN32
143
/* Windows does not support speeds of 134, 150, or 200 */
11 rm5248 144
                SPEED_SWITCH(134,newio);
145
                SPEED_SWITCH(150,newio);
146
                SPEED_SWITCH(200,newio);
13 rm5248 147
#endif
11 rm5248 148
                SPEED_SWITCH(300,newio);
149
                SPEED_SWITCH(600,newio);
150
                SPEED_SWITCH(1200,newio);
13 rm5248 151
#ifndef _WIN32
152
/* Windows does not support 1800 */
11 rm5248 153
                SPEED_SWITCH(1800,newio);
13 rm5248 154
#endif
11 rm5248 155
                SPEED_SWITCH(2400,newio);
156
                SPEED_SWITCH(4800,newio);
157
                SPEED_SWITCH(9600,newio);
158
                SPEED_SWITCH(19200,newio);
159
                SPEED_SWITCH(38400,newio);
160
                SPEED_SWITCH(115200,newio);
161
        }
162
 
13 rm5248 163
        SET_SERIAL_PORT_STRUCT( desc->port, newio );
164
 
165
        return 1;
166
}
167
 
55 rm5248 168
static inline int set_raw_input( struct port_descriptor* desc ){
14 rm5248 169
        GET_SERIAL_PORT_STRUCT( desc->port, newio );
170
 
171
#ifdef _WIN32
23 rm5248 172
        newio.fBinary = TRUE;
173
        newio.fParity = TRUE;
174
        newio.fOutxCtsFlow = FALSE;
175
        newio.fOutxDsrFlow = FALSE;
176
        newio.fDtrControl = DTR_CONTROL_DISABLE;
177
        newio.fDsrSensitivity = FALSE;
178
        newio.fOutX = FALSE;
179
        newio.fInX = FALSE;
180
        newio.fNull = FALSE;
181
        newio.fRtsControl = FALSE;
182
 
183
        //Set the timeouts
184
        {
185
                COMMTIMEOUTS timeouts = {0};
27 rm5248 186
                timeouts.ReadIntervalTimeout = MAXDWORD;
23 rm5248 187
                timeouts.ReadTotalTimeoutMultiplier = 0;
188
                timeouts.ReadTotalTimeoutConstant = 0;
27 rm5248 189
                timeouts.WriteTotalTimeoutMultiplier = 0;
190
                timeouts.WriteTotalTimeoutConstant = 0;
23 rm5248 191
                if( SetCommTimeouts( desc->port, &timeouts ) == 0 ){
192
                printf("bad timeout\n"); fflush(stdout);}
193
        }
14 rm5248 194
#else
195
        newio.c_iflag |= IGNBRK;
196
        newio.c_iflag &= ~BRKINT;
197
        newio.c_iflag &= ~ICRNL;
198
        newio.c_oflag = 0;
199
        newio.c_lflag = 0;
200
        newio.c_cc[VTIME] = 0;
201
        newio.c_cc[VMIN] = 1;
202
#endif
203
 
204
        SET_SERIAL_PORT_STRUCT( desc->port, newio );
205
 
206
        return 1;
207
}
208
 
23 rm5248 209
/**
210
 * @param data_bits The number of data bits
211
 */
55 rm5248 212
static inline int set_data_bits( struct port_descriptor* desc, int data_bits ){
13 rm5248 213
        GET_SERIAL_PORT_STRUCT( desc->port, newio );
214
 
215
#ifdef _WIN32 
216
        newio.ByteSize = data_bits;
217
#else
14 rm5248 218
        newio.c_cflag &= ~CSIZE;
219
        if( data_bits == 8 ){
220
                newio.c_cflag |= CS8;
221
        }else if( data_bits == 7 ){
222
                newio.c_cflag |= CS7;
223
        }else if( data_bits == 6 ){
224
                newio.c_cflag |= CS6;
225
        }else if( data_bits == 5 ){
226
                newio.c_cflag |= CS5;
227
        }
13 rm5248 228
#endif
229
 
230
        SET_SERIAL_PORT_STRUCT( desc->port, newio );
231
 
232
        return 1;
233
}
234
 
23 rm5248 235
/**
236
 * @param stop_bits 1 for 1, 2 for 2
237
 */
55 rm5248 238
static inline int set_stop_bits( struct port_descriptor* desc, int stop_bits ){
13 rm5248 239
        GET_SERIAL_PORT_STRUCT( desc->port, newio );
240
 
241
#ifdef _WIN32 
242
        if( stop_bits == 1 ){
243
                newio.StopBits = ONESTOPBIT;
244
        }else if( stop_bits == 2 ){
245
                newio.StopBits = TWOSTOPBITS;
11 rm5248 246
        }
13 rm5248 247
#else
14 rm5248 248
        if( stop_bits == 1 ){
249
                newio.c_cflag &= ~CSTOPB;
250
        }else if( stop_bits == 2 ){
251
                newio.c_cflag |= CSTOPB;
252
        }
13 rm5248 253
#endif
254
 
255
        SET_SERIAL_PORT_STRUCT( desc->port, newio );
11 rm5248 256
 
257
        return 1;
13 rm5248 258
}
11 rm5248 259
 
23 rm5248 260
/**
261
 * @param parity 0 for no parity, 1 for odd parity, 2 for even parity
262
 */
55 rm5248 263
static inline int set_parity( struct port_descriptor* desc, int parity ){
13 rm5248 264
        GET_SERIAL_PORT_STRUCT( desc->port, newio );
265
 
266
#ifdef _WIN32 
267
        if( parity == 0 ){
268
                newio.Parity = NOPARITY;
269
        }else if( parity == 1 ){
270
                newio.Parity = ODDPARITY;
271
        }else if( parity == 2 ){
272
                newio.Parity = EVENPARITY;
273
        }
274
#else
62 rm5248 275
        newio.c_iflag &= ~IGNPAR;
276
        newio.c_cflag &= ~( PARODD | PARENB );
14 rm5248 277
        if( parity == 0 ){
57 rm5248 278
                newio.c_iflag |= IGNPAR;
14 rm5248 279
        }else if( parity == 1 ){
280
                newio.c_cflag |= PARODD;
281
        }else if( parity == 2 ){
282
                newio.c_cflag |= PARENB;
283
        }
13 rm5248 284
#endif
285
 
286
        SET_SERIAL_PORT_STRUCT( desc->port, newio );
287
 
288
        return 1;
11 rm5248 289
}
290
 
23 rm5248 291
/**
292
 * @param flow_control 0 for none, 1 for hardware, 2 for software
293
 */
55 rm5248 294
static inline int set_flow_control( struct port_descriptor* desc, int flow_control ){
13 rm5248 295
        GET_SERIAL_PORT_STRUCT( desc->port, newio );
296
 
23 rm5248 297
#ifdef _WIN32
298
        if( flow_control == 0 ){
30 rm5248 299
                newio.fOutxCtsFlow = FALSE;
300
                newio.fRtsControl = FALSE;
301
                newio.fOutX = FALSE;
302
                newio.fInX = FALSE;
23 rm5248 303
        }else if( flow_control == 1 ){
30 rm5248 304
                newio.fOutxCtsFlow = TRUE;
305
                newio.fRtsControl = TRUE;
306
                newio.fOutX = FALSE;
307
                newio.fInX = FALSE;
23 rm5248 308
        }else if( flow_control == 2 ){
30 rm5248 309
                newio.fOutxCtsFlow = FALSE;
310
                newio.fRtsControl = FALSE;
311
                newio.fOutX = TRUE;
312
                newio.fInX = TRUE;
23 rm5248 313
        }
13 rm5248 314
#else
62 rm5248 315
        newio.c_iflag &= ~( IXON | IXOFF | IXANY );
316
        newio.c_cflag &= ~HW_FLOW;
14 rm5248 317
        if( flow_control == 0 ){
57 rm5248 318
                newio.c_iflag &= ~( IXON | IXOFF | IXANY );
14 rm5248 319
        }else if( flow_control == 1 ){
320
                newio.c_cflag |= HW_FLOW;
321
        }else if( flow_control == 2 ){
57 rm5248 322
                newio.c_iflag |= ( IXON | IXOFF | IXANY );
14 rm5248 323
        }
13 rm5248 324
#endif
325
 
326
        SET_SERIAL_PORT_STRUCT( desc->port, newio );
327
 
328
        return 1;
329
}
330
 
55 rm5248 331
static inline void throw_io_exception( JNIEnv * env, int errorNumber ){
27 rm5248 332
#ifdef _WIN32
333
        LPTSTR error_text = NULL;
334
        jclass exception_class;
335
        (*env)->ExceptionDescribe( env );
336
        (*env)->ExceptionClear( env );
337
        exception_class = (*env)->FindClass(env, "java/io/IOException");
338
 
339
        FormatMessage(
340
                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
341
                NULL,
342
                errorNumber,
343
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
344
                (LPTSTR)&error_text,
345
                0,
346
                NULL );
347
        (*env)->ThrowNew(env, exception_class, error_text );
348
        LocalFree( error_text );
349
#else
350
        jclass exception_class;
351
        (*env)->ExceptionDescribe( env );
352
        (*env)->ExceptionClear( env );
353
        exception_class = (*env)->FindClass(env, "java/io/IOException");
354
        (*env)->ThrowNew(env, exception_class, strerror( errorNumber ) );
355
#endif /* _WIN32 */
356
}
357
 
55 rm5248 358
static inline void throw_io_exception_message( JNIEnv * env, const char* message ){
27 rm5248 359
        jclass exception_class;
360
        (*env)->ExceptionDescribe( env );
361
        (*env)->ExceptionClear( env );
362
        exception_class = (*env)->FindClass(env, "java/io/IOException");
363
        (*env)->ThrowNew(env, exception_class, message );
364
}
365
 
55 rm5248 366
static inline struct port_descriptor* get_port_descriptor( JNIEnv* env, jobject obj ){
367
        int array_pos;
368
        struct port_descriptor* desc;
369
 
370
        array_pos = get_handle( env, obj );
371
        if( array_pos < 0 || array_pos > port_list_size ){
372
                throw_io_exception_message( env, "Unable to get handle" );
373
                return NULL;
374
        }
375
        desc = port_list[ array_pos ];
376
        if( desc == NULL ){
377
                throw_io_exception_message( env, "Unable to get descriptor" );
378
                return NULL;
379
        }
380
 
381
        return desc;
382
}
383
 
8 rm5248 384
//
385
// JNI Methods
386
//
387
 
388
/*
389
 * Class:     com_rm5248_serial_SerialPort
390
 * Method:    openPort
11 rm5248 391
 * Signature: (Ljava/lang/String;IIIII)I
8 rm5248 392
 */
393
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_openPort
11 rm5248 394
  (JNIEnv * env, jobject obj, jstring port, jint baudRate, jint dataBits, jint stopBits, jint parity, jint flowControl){
8 rm5248 395
        struct port_descriptor* new_port;
396
        int list_pos;
397
        int found = 0;
398
        const char* port_to_open;
399
        jboolean iscopy;
400
 
401
        port_to_open = (*env)->GetStringUTFChars( env, port, &iscopy );
402
 
403
        if( port_list == NULL ){
404
                port_list = malloc( sizeof( struct port_descriptor* ) * 10 );
405
                port_list_size = 10;
406
                for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
407
                        port_list[ list_pos ] = NULL;
408
                }
409
        }
410
 
18 rm5248 411
        //Search thru the port_list, find the first one that is NULL
8 rm5248 412
        for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
18 rm5248 413
                if( port_list[ list_pos ] == NULL ){
8 rm5248 414
                        found = 1;
415
                        break;
416
                }
417
        }
418
 
419
        if( !found ){
420
                //no free slots.  Expand our array by 10 elements
421
                struct port_descriptor** tmpPortDesc;
422
                tmpPortDesc = malloc( sizeof( struct port_descriptor* ) * ( port_list_size + 10 ) );
423
 
424
                //put all elements into the new array
425
                for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
426
                        tmpPortDesc[ list_pos ] = port_list[ list_pos ];
427
                }
428
                ++list_pos; //put the place to insert the new record one past the old records
429
 
430
                port_list_size += 10;
431
 
432
                //free the old array, set it to the new one
433
                free( port_list );
434
                port_list = tmpPortDesc;
435
        }
436
 
437
        //at this point, list_pos points to a NULL location in our array
438
        new_port = malloc( sizeof( struct port_descriptor ) );
439
 
440
        //Now, let's get to the actual opening of our port
13 rm5248 441
#ifdef _WIN32
68 rm5248 442
        {
443
                //GOD DAMN IT WINDOWS http://support.microsoft.com/kb/115831
71 rm5248 444
                char* special_port = malloc( strlen( port_to_open ) + 5 );
68 rm5248 445
                memcpy( special_port, "\\\\.\\", 4 );
446
                memcpy( special_port + 4, port_to_open, strlen( port_to_open ) + 1 );
447
                new_port->port = CreateFile( special_port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
448
                free( special_port );
449
        }
13 rm5248 450
        if( new_port->port == INVALID_HANDLE_VALUE ){
451
                if( GetLastError() == ERROR_FILE_NOT_FOUND ){
452
                        LPTSTR error_text = NULL;
453
                        jclass exception_class;
454
 
455
                        FormatMessage(
456
                                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
457
                                NULL,
458
                                GetLastError(),
459
                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
460
                                (LPTSTR)&error_text,
461
                                0,
462
                                NULL );
463
 
464
                        (*env)->ExceptionDescribe( env );
465
                        (*env)->ExceptionClear( env );
466
                        exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
467
                        (*env)->ThrowNew(env, exception_class, error_text );
468
                        free( new_port );
469
                        LocalFree( error_text );
470
                        return -1;
471
                }
472
        }
27 rm5248 473
 
54 rm5248 474
        {
27 rm5248 475
                //Let's check to see if this is a serial port
476
                DCB io_name = {0};
477
                io_name.DCBlength = sizeof( io_name );
478
                if (!GetCommState( new_port->port, &io_name ) ) {
55 rm5248 479
                        LPTSTR error_text = NULL;
27 rm5248 480
                        jclass exception_class;
481
                        (*env)->ExceptionDescribe( env );
482
                        (*env)->ExceptionClear( env );
483
                        exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
484
                        (*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
485
                        free( new_port );
486
                        return -1;
487
                }
488
        }
489
 
8 rm5248 490
#else
77 rm5248 491
        pthread_mutex_init( &(new_port->in_use), NULL );
8 rm5248 492
        new_port->port = open( port_to_open, O_RDWR );
493
        if( new_port->port < 0 && errno == ENOENT ){
494
                //That's not a valid serial port, error out
495
                jclass exception_class;
496
                (*env)->ExceptionDescribe( env );
497
                (*env)->ExceptionClear( env );
498
                exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
499
                (*env)->ThrowNew(env, exception_class, strerror( errno ) );
500
                free( new_port );
13 rm5248 501
                return -1;
8 rm5248 502
        }else if( new_port->port < 0 ){
503
                jclass exception_class;
504
                (*env)->ExceptionDescribe( env );
505
                (*env)->ExceptionClear( env );
506
                exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
507
                (*env)->ThrowNew(env, exception_class, strerror( errno ) );
508
                free( new_port );
13 rm5248 509
                return -1;
8 rm5248 510
        }
27 rm5248 511
 
512
        {
513
                struct termios io_name;
28 rm5248 514
                if( tcgetattr( new_port->port, &io_name ) < 0 ){
32 rm5248 515
                        if( errno == ENOTTY ){
27 rm5248 516
                                //This is apparently not a serial port
517
                                jclass exception_class;
518
                                (*env)->ExceptionDescribe( env );
519
                                (*env)->ExceptionClear( env );
520
                                exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
521
                                (*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
522
                                free( new_port );
523
                                return -1;
524
                        }
525
                }
526
        }
8 rm5248 527
#endif /* __WIN32 */
528
 
529
 
27 rm5248 530
 
11 rm5248 531
        //Set the baud rate
57 rm5248 532
        if( set_baud_rate( new_port, baudRate ) < 0 ){
533
                        throw_io_exception_message( env, "Unable to set baud rate" );
534
                        return 0;
535
        }
27 rm5248 536
        set_raw_input( new_port );
537
        //Set the data bits( character size )
538
        set_data_bits( new_port, dataBits );
539
        //Set the stop bits
540
        set_stop_bits( new_port, stopBits );
541
        //Set the parity
542
        set_parity( new_port, parity );
543
        //Set the flow control
544
        set_flow_control( new_port, flowControl );
545
 
546
        //Only set the new_port to be in our array as the last instruction
547
        //If there are any errors, we will have returned long before this
548
        port_list[ list_pos ] = new_port;
549
 
550
        return list_pos;
551
}
552
 
553
/*
554
 * Class:     com_rm5248_serial_SerialPort
555
 * Method:    openPort
556
 * Signature: (Ljava/lang/String;)I
557
 */
558
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_openPort__Ljava_lang_String_2
559
  (JNIEnv * env, jobject obj, jstring port){
560
        struct port_descriptor* new_port;
561
        int list_pos;
562
        int found = 0;
563
        const char* port_to_open;
564
        jboolean iscopy;
565
 
566
        port_to_open = (*env)->GetStringUTFChars( env, port, &iscopy );
567
 
568
        if( port_list == NULL ){
569
                port_list = malloc( sizeof( struct port_descriptor* ) * 10 );
570
                port_list_size = 10;
571
                for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
572
                        port_list[ list_pos ] = NULL;
573
                }
574
        }
575
 
576
        //Search thru the port_list, find the first one that is NULL
577
        for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
578
                if( port_list[ list_pos ] == NULL ){
579
                        found = 1;
580
                        break;
581
                }
582
        }
583
 
584
        if( !found ){
585
                //no free slots.  Expand our array by 10 elements
586
                struct port_descriptor** tmpPortDesc;
587
                tmpPortDesc = malloc( sizeof( struct port_descriptor* ) * ( port_list_size + 10 ) );
588
 
589
                //put all elements into the new array
590
                for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
591
                        tmpPortDesc[ list_pos ] = port_list[ list_pos ];
592
                }
593
                ++list_pos; //put the place to insert the new record one past the old records
594
 
595
                port_list_size += 10;
596
 
597
                //free the old array, set it to the new one
598
                free( port_list );
599
                port_list = tmpPortDesc;
600
        }
601
 
602
        //at this point, list_pos points to a NULL location in our array
603
        new_port = malloc( sizeof( struct port_descriptor ) );
604
 
605
        //Now, let's get to the actual opening of our port
606
#ifdef _WIN32
68 rm5248 607
        {
71 rm5248 608
                char* special_port = malloc( strlen( port_to_open ) + 5 );
68 rm5248 609
                memcpy( special_port, "\\\\.\\", 4 );
610
                memcpy( special_port + 4, port_to_open, strlen( port_to_open ) + 1 );
611
                new_port->port = CreateFile( special_port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
612
                free( special_port );
613
        }
27 rm5248 614
        if( new_port->port == INVALID_HANDLE_VALUE ){
615
                if( GetLastError() == ERROR_FILE_NOT_FOUND ){
616
                        LPTSTR error_text = NULL;
617
                        jclass exception_class;
618
 
619
                        FormatMessage(
620
                                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
621
                                NULL,
622
                                GetLastError(),
623
                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
624
                                (LPTSTR)&error_text,
625
                                0,
626
                                NULL );
627
 
628
                        (*env)->ExceptionDescribe( env );
629
                        (*env)->ExceptionClear( env );
630
                        exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
631
                        (*env)->ThrowNew(env, exception_class, error_text );
632
                        free( new_port );
633
                        LocalFree( error_text );
634
                        return -1;
635
                }
636
        }
637
 
638
        {
639
                //Let's check to see if this is a serial port
640
                DCB io_name = {0};
641
                io_name.DCBlength = sizeof( io_name );
642
                if (!GetCommState( new_port->port, &io_name ) ) {
55 rm5248 643
                        LPTSTR error_text = NULL;
27 rm5248 644
                        jclass exception_class;
645
                        (*env)->ExceptionDescribe( env );
646
                        (*env)->ExceptionClear( env );
647
                        exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
648
                        (*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
649
                        free( new_port );
650
                        return -1;
651
                }
652
        }
653
#else
77 rm5248 654
        pthread_mutex_init( &(new_port->in_use), NULL );
27 rm5248 655
        new_port->port = open( port_to_open, O_RDWR );
656
        if( new_port->port < 0 && errno == ENOENT ){
657
                //That's not a valid serial port, error out
13 rm5248 658
                jclass exception_class;
659
                (*env)->ExceptionDescribe( env );
660
                (*env)->ExceptionClear( env );
27 rm5248 661
                exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
662
                (*env)->ThrowNew(env, exception_class, strerror( errno ) );
13 rm5248 663
                free( new_port );
27 rm5248 664
                return -1;
665
        }else if( new_port->port < 0 ){
13 rm5248 666
                jclass exception_class;
667
                (*env)->ExceptionDescribe( env );
668
                (*env)->ExceptionClear( env );
27 rm5248 669
                exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
670
                (*env)->ThrowNew(env, exception_class, strerror( errno ) );
13 rm5248 671
                free( new_port );
672
                return -1;
673
        }
27 rm5248 674
 
675
        {
676
                struct termios io_name;
28 rm5248 677
                if( tcgetattr( new_port->port, &io_name ) < 0 ){
32 rm5248 678
                        if( errno == ENOTTY ){
27 rm5248 679
                                //This is apparently not a serial port
680
                                jclass exception_class;
681
                                (*env)->ExceptionDescribe( env );
682
                                (*env)->ExceptionClear( env );
683
                                exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
684
                                (*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
685
                                free( new_port );
686
                                return -1;
687
                        }
688
                }
689
        }
690
#endif /* __WIN32 */
11 rm5248 691
 
27 rm5248 692
 
13 rm5248 693
        //Only set the new_port to be in our array as the last instruction
694
        //If there are any errors, we will have returned long before this
695
        port_list[ list_pos ] = new_port;
27 rm5248 696
 
8 rm5248 697
        return list_pos;
698
}
699
 
700
/*
701
 * Class:     com_rm5248_serial_SerialPort
27 rm5248 702
 * Method:    doClose
703
 * Signature: ()V
704
 */
705
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialPort_doClose
706
  (JNIEnv * env, jobject obj){
55 rm5248 707
        //Note: We can't use get_serial_port_struct here, beacuse we need to set
708
        //the position in the array to NULL
709
        int array_pos;
27 rm5248 710
        struct port_descriptor* desc;
55 rm5248 711
 
712
        array_pos = get_handle( env, obj );
713
        if( array_pos < 0 || array_pos > port_list_size ){
714
                throw_io_exception_message( env, "Unable to get handle" );
715
                return;
716
        }
717
        desc = port_list[ array_pos ];
718
        if( desc == NULL ){
719
                throw_io_exception_message( env, "Unable to get descriptor" );
720
                return;
27 rm5248 721
        }
68 rm5248 722
 
27 rm5248 723
        close( desc->port );
77 rm5248 724
#ifndef _WIN32
725
        pthread_mutex_lock( &(desc->in_use) );
726
        pthread_mutex_unlock( &(desc->in_use) );
727
#endif
68 rm5248 728
        free( port_list[ array_pos ] );
27 rm5248 729
        port_list[ array_pos ] = NULL;
730
}
731
 
732
/*
733
 * Class:     com_rm5248_serial_SerialPort
8 rm5248 734
 * Method:    setBaudRate
735
 * Signature: (I)Z
736
 */
737
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setBaudRate
738
  (JNIEnv * env, jobject obj, jint baud_rate ){
739
        struct port_descriptor* desc;
740
 
55 rm5248 741
        desc = get_port_descriptor( env, obj );
57 rm5248 742
 
55 rm5248 743
        if( desc == NULL ){
744
                return 0;
745
        }
8 rm5248 746
 
11 rm5248 747
        return set_baud_rate( desc, baud_rate );
8 rm5248 748
}
749
 
750
/*
751
 * Class:     com_rm5248_serial_SerialPort
20 rm5248 752
 * Method:    getBaudRateInternal
753
 * Signature: ()I
754
 */
755
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getBaudRateInternal
756
  (JNIEnv * env, jobject obj){
757
        struct port_descriptor* desc;
758
 
55 rm5248 759
        desc = get_port_descriptor( env, obj );
760
        if( desc == NULL ){
761
                return 0;
762
        }
20 rm5248 763
 
764
        //Now, let's get the baud rate information
765
        {
766
                GET_SERIAL_PORT_STRUCT( desc->port, newio );
767
#ifdef _WIN32
23 rm5248 768
                GetCommState( desc->port, &newio );
769
                switch( newio.BaudRate ){
20 rm5248 770
#else
771
                switch( cfgetispeed( &newio ) ){
772
                GET_SPEED_SWITCH( 0, newio );
773
                GET_SPEED_SWITCH( 50, newio );
774
                GET_SPEED_SWITCH( 75, newio );
23 rm5248 775
#endif /* _WIN32 */
20 rm5248 776
                GET_SPEED_SWITCH( 110, newio );
23 rm5248 777
#ifndef _WIN32
20 rm5248 778
                GET_SPEED_SWITCH( 134, newio );
779
                GET_SPEED_SWITCH( 150, newio );
780
                GET_SPEED_SWITCH( 200, newio );
23 rm5248 781
#endif /* _WIN32 */
20 rm5248 782
                GET_SPEED_SWITCH( 300, newio );
783
                GET_SPEED_SWITCH( 600, newio );
784
                GET_SPEED_SWITCH( 1200, newio );
23 rm5248 785
#ifndef _WIN32
20 rm5248 786
                GET_SPEED_SWITCH( 1800, newio );
23 rm5248 787
#endif /* _WIN32 */
20 rm5248 788
                GET_SPEED_SWITCH( 2400, newio );
789
                GET_SPEED_SWITCH( 4800, newio );
790
                GET_SPEED_SWITCH( 9600, newio );
791
                GET_SPEED_SWITCH( 19200, newio );
792
                GET_SPEED_SWITCH( 38400, newio );
793
                GET_SPEED_SWITCH( 115200, newio );
794
                default:
795
                        return 0;
796
                } /* end switch */
797
        }
798
 
799
}
800
 
801
/*
802
 * Class:     com_rm5248_serial_SerialPort
8 rm5248 803
 * Method:    setStopBits
804
 * Signature: (I)Z
805
 */
806
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setStopBits
807
  (JNIEnv * env, jobject obj, jint bits){
13 rm5248 808
        struct port_descriptor* desc;
809
 
55 rm5248 810
        desc = get_port_descriptor( env, obj );
13 rm5248 811
        if( desc == NULL ){
812
                return 0;
813
        }
8 rm5248 814
 
13 rm5248 815
        return set_stop_bits( desc, bits );
8 rm5248 816
}
817
 
818
/*
819
 * Class:     com_rm5248_serial_SerialPort
20 rm5248 820
 * Method:    getStopBitsInternal
821
 * Signature: ()I
822
 */
823
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getStopBitsInternal
824
  (JNIEnv * env, jobject obj){
825
        struct port_descriptor* desc;
826
 
55 rm5248 827
        desc = get_port_descriptor( env, obj );
20 rm5248 828
        if( desc == NULL ){
829
                return 0;
830
        }
831
 
832
        {
833
                GET_SERIAL_PORT_STRUCT( desc->port, newio );
834
#ifdef _WIN32
23 rm5248 835
                if( newio.StopBits == 1 ){
836
                        return 1;
837
                }else if( newio.StopBits == 2 ){
838
                        return 2;
839
                }else{
840
                        return -1;
841
                }
20 rm5248 842
#else
843
                if( newio.c_cflag & CSTOPB ){
844
                        return 2;
845
                }else{
846
                        return 1;
847
                }
848
#endif
849
        }
850
}
851
/*
852
 * Class:     com_rm5248_serial_SerialPort
8 rm5248 853
 * Method:    setCharSize
854
 * Signature: (I)Z
855
 */
856
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setCharSize
857
  (JNIEnv * env, jobject obj, jint size){
13 rm5248 858
        struct port_descriptor* desc;
8 rm5248 859
 
55 rm5248 860
        desc = get_port_descriptor( env, obj );
13 rm5248 861
        if( desc == NULL ){
862
                return 0;
863
        }
864
 
865
        return set_data_bits( desc, size );
8 rm5248 866
}
867
 
868
/*
11 rm5248 869
 * Class:     com_rm5248_serial_SerialPort
20 rm5248 870
 * Method:    getCharSizeInternal
871
 * Signature: ()I
872
 */
873
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getCharSizeInternal
874
  (JNIEnv * env, jobject obj){
875
        struct port_descriptor* desc;
876
 
55 rm5248 877
        desc = get_port_descriptor( env, obj );
20 rm5248 878
        if( desc == NULL ){
879
                return 0;
880
        }
881
 
882
        //Now get the char size
883
        {
884
                GET_SERIAL_PORT_STRUCT( desc->port, newio );
885
 
886
#ifdef _WIN32
23 rm5248 887
                return newio.ByteSize;
20 rm5248 888
#else
889
                if( ( newio.c_cflag | CS8 ) == CS8 ){
890
                        return 8;
891
                }else if( ( newio.c_cflag | CS7 ) == CS7 ){
892
                        return 7;
893
                }else if( ( newio.c_cflag | CS6 ) == CS6 ){
894
                        return 6;
895
                }else if( ( newio.c_cflag | CS5 ) == CS5 ){
896
                        return 5;
897
                }else{
898
                        return 0;
899
                }
900
#endif
901
        }
902
 
903
}
904
 
905
/*
906
 * Class:     com_rm5248_serial_SerialPort
11 rm5248 907
 * Method:    setParity
908
 * Signature: (I)Z
909
 */
910
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setParity
911
  (JNIEnv * env, jobject obj, jint parity){
13 rm5248 912
        struct port_descriptor* desc;
11 rm5248 913
 
55 rm5248 914
        desc = get_port_descriptor( env, obj );
13 rm5248 915
        if( desc == NULL ){
916
                return 0;
30 rm5248 917
        }      
13 rm5248 918
 
919
        return set_parity( desc, parity );
11 rm5248 920
}
921
 
20 rm5248 922
/*
923
 * Class:     com_rm5248_serial_SerialPort
924
 * Method:    getParityInternal
925
 * Signature: ()I
926
 */
927
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getParityInternal
928
  (JNIEnv * env, jobject obj){
929
        struct port_descriptor* desc;
930
 
55 rm5248 931
        desc = get_port_descriptor( env, obj );
20 rm5248 932
        if( desc == NULL ){
933
                return 0;
934
        }
935
 
936
        {
937
                GET_SERIAL_PORT_STRUCT( desc->port, newio );
938
#ifdef _WIN32
23 rm5248 939
                if( newio.Parity == NOPARITY ){
940
                        return 0;
941
                }else if( newio.Parity == ODDPARITY ){
942
                        return 1;
943
                }else if( newio.Parity == EVENPARITY ){
944
                        return 2;
945
                }else{
946
                        return -1;
947
                }
20 rm5248 948
#else
949
                if( !( newio.c_cflag & PARENB ) ){
950
                        //No parity
951
                        return 0;
952
                }else if( newio.c_cflag & PARODD ){
953
                        //Odd parity
954
                        return 1;
955
                }else if( !( newio.c_cflag & PARODD ) ){
956
                        //Even parity
957
                        return 2;
958
                }else{
959
                        return -1;
960
                }
961
#endif
962
        }
963
 
964
}
965
 
27 rm5248 966
/*
967
 * Class:     com_rm5248_serial_SerialPort
968
 * Method:    setFlowControl
969
 * Signature: (I)Z
970
 */
971
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setFlowControl
972
  (JNIEnv * env, jobject obj, jint flow){
30 rm5248 973
        struct port_descriptor* desc;
974
 
55 rm5248 975
        desc = get_port_descriptor( env, obj );
30 rm5248 976
        if( desc == NULL ){
977
                return 0;
978
        }
979
 
31 rm5248 980
        return set_flow_control( desc, flow );
27 rm5248 981
}
982
 
983
/*
984
 * Class:     com_rm5248_serial_SerialPort
985
 * Method:    getFlowControlInternal
986
 * Signature: ()I
987
 */
988
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getFlowControlInternal
989
  (JNIEnv * env, jobject obj){
990
        struct port_descriptor* desc;
991
 
55 rm5248 992
        desc = get_port_descriptor( env, obj );
30 rm5248 993
        if( desc == NULL ){
994
                return 0;
995
        }
996
 
27 rm5248 997
        {
998
                GET_SERIAL_PORT_STRUCT( desc->port, newio );
999
#ifdef _WIN32
30 rm5248 1000
                if( newio.fOutX == TRUE && newio.fInX == TRUE ){
1001
                        return 2;
1002
                }else if( newio.fRtsControl == TRUE && newio.fOutxCtsFlow == TRUE ){
1003
                        return 1;
1004
                }else{
1005
                        return 0;
1006
                }
27 rm5248 1007
#else
32 rm5248 1008
                if( newio.c_cflag & ~( IXON ) &&
1009
                        newio.c_cflag & ~( IXOFF ) &&
1010
                        newio.c_cflag & ~( IXANY ) ){
1011
                        return 0;
1012
                }else if( newio.c_cflag & HW_FLOW ){
1013
                        return 1;
1014
                }else if( newio.c_cflag & ( IXON ) &&
1015
                        newio.c_cflag & ( IXOFF ) &&
1016
                        newio.c_cflag & ( IXANY ) ){
1017
                        return 2;
1018
                }
27 rm5248 1019
#endif /* _WIN32 */
1020
        }
32 rm5248 1021
 
1022
        return -1;
27 rm5248 1023
}
1024
 
31 rm5248 1025
/*
1026
 * Class:     com_rm5248_serial_SerialPort
1027
 * Method:    getSerialLineStateInternalNonblocking
1028
 * Signature: ()I
1029
 */
1030
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getSerialLineStateInternalNonblocking
1031
  (JNIEnv * env, jobject obj ){
34 rm5248 1032
        struct port_descriptor* desc;
35 rm5248 1033
        jint ret_val;
31 rm5248 1034
 
55 rm5248 1035
        desc = get_port_descriptor( env, obj );
34 rm5248 1036
        if( desc == NULL ){
1037
                return 0;
1038
        }
1039
 
36 rm5248 1040
        ret_val = 0;
1041
 
1042
        {      
35 rm5248 1043
#ifdef _WIN32
36 rm5248 1044
                DWORD get_val;
1045
                if( GetCommModemStatus( desc->port, &get_val ) == 0 ){
1046
                        throw_io_exception( env, GetLastError() );
1047
                        return -1;
1048
                }
1049
 
1050
                if( get_val & MS_CTS_ON ){
1051
                        // CTS
1052
                        ret_val |= ( 0x01 << 1 );
1053
                }
1054
 
1055
                if( get_val & MS_DSR_ON ){
1056
                        // Data Set Ready
1057
                        ret_val |= ( 0x01 << 2 );
1058
                }
1059
 
65 rm5248 1060
                if( winDTR ){
1061
                        ret_val |= ( 0x01 << 3 );
1062
                }
1063
 
1064
                if( winRTS ){
1065
                        ret_val |= ( 0x01 << 4 );
1066
                }
1067
 
36 rm5248 1068
                if( get_val & MS_RING_ON ){
1069
                        // Ring Indicator
1070
                        ret_val |= ( 0x01 << 5 );
1071
                }
35 rm5248 1072
#else
36 rm5248 1073
                int get_val;
35 rm5248 1074
                if( ioctl( desc->port, TIOCMGET, &get_val ) < 0 ){
1075
                        throw_io_exception( env, errno );
1076
                        return -1;
1077
                }
1078
 
1079
                if( get_val & TIOCM_CD ){
1080
                        // Carrier detect
1081
                        ret_val |= 0x01;
1082
                }
1083
 
1084
                if( get_val & TIOCM_CTS ){
1085
                        // CTS
1086
                        ret_val |= ( 0x01 << 1 );
1087
                }
1088
 
1089
                if( get_val & TIOCM_DSR ){
1090
                        // Data Set Ready
1091
                        ret_val |= ( 0x01 << 2 );
1092
                }
1093
 
1094
                if( get_val & TIOCM_DTR ){
1095
                        // Data Terminal Ready
1096
                        ret_val |= ( 0x01 << 3 );
1097
                }
1098
 
1099
                if( get_val & TIOCM_RTS ){
1100
                        // Request To Send
1101
                        ret_val |= ( 0x01 << 4 );
1102
                }
1103
 
1104
                if( get_val & TIOCM_RI ){
1105
                        // Ring Indicator
1106
                        ret_val |= ( 0x01 << 5 );
1107
                }
1108
#endif
1109
        }
1110
 
1111
        return ret_val;
31 rm5248 1112
}
1113
 
40 rm5248 1114
/*
1115
 * Class:     com_rm5248_serial_SerialPort
1116
 * Method:    setSerialLineStateInternal
1117
 * Signature: (Lcom/rm5248/serial/SerialLineState;)I
1118
 */
1119
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_setSerialLineStateInternal
1120
  (JNIEnv * env, jobject obj, jobject serial){
1121
        struct port_descriptor* desc;
1122
        jint ret_val;
1123
 
55 rm5248 1124
        desc = get_port_descriptor( env, obj );
40 rm5248 1125
        if( desc == NULL ){
1126
                return 0;
1127
        }
1128
 
1129
        ret_val = 0;
1130
 
1131
#ifdef _WIN32
1132
        if( get_bool( env, serial, "dataTerminalReady" ) ){
1133
                if( !EscapeCommFunction( desc->port, SETDTR ) ){
1134
                        throw_io_exception_message( env, "Could not set DTR" );
1135
                        return -1;
1136
                }
65 rm5248 1137
                winDTR = 1;
40 rm5248 1138
        }else{
1139
                if( !EscapeCommFunction( desc->port, CLRDTR ) ){
1140
                        throw_io_exception_message( env, "Could not set DTR" );
1141
                        return -1;
1142
                }
65 rm5248 1143
                winDTR = 0;
40 rm5248 1144
        }
1145
 
1146
        if( get_bool( env, serial, "requestToSend" ) ){
1147
                if( !EscapeCommFunction( desc->port, SETRTS ) ){
1148
                        throw_io_exception_message( env, "Could not set RTS" );
1149
                        return -1;
1150
                }
65 rm5248 1151
                winRTS = 1;
40 rm5248 1152
        }else{
1153
                if( !EscapeCommFunction( desc->port, CLRRTS ) ){
1154
                        throw_io_exception_message( env, "Could not set RTS" );
1155
                        return -1;
1156
                }
65 rm5248 1157
                winRTS = 0;
40 rm5248 1158
        }
1159
#else
62 rm5248 1160
        int toSet = 0;
40 rm5248 1161
 
62 rm5248 1162
        if( ioctl( desc->port, TIOCMGET, &toSet ) < 0 ){
1163
                throw_io_exception_message( env, "Could not get port settings" );
1164
                return -1;
40 rm5248 1165
        }
1166
 
1167
        if( get_bool( env, serial, "dataTerminalReady" ) ){
62 rm5248 1168
                toSet |= TIOCM_DTR;
40 rm5248 1169
        }else{
62 rm5248 1170
                toSet &= ~TIOCM_DTR;
40 rm5248 1171
        }
1172
 
62 rm5248 1173
        if( get_bool( env, serial, "requestToSend" ) ){
1174
                toSet |= TIOCM_RTS;
40 rm5248 1175
        }else{
62 rm5248 1176
                toSet &= ~TIOCM_RTS;
40 rm5248 1177
        }
1178
 
62 rm5248 1179
        if( ioctl( desc->port, TIOCMSET, &toSet ) < 0 ){
1180
                throw_io_exception_message( env, "Could not set port settings" );
40 rm5248 1181
        }
1182
#endif
1183
 
1184
        return ret_val;
1185
}
1186
 
38 rm5248 1187
//
1188
// ------------------------------------------------------------------------
1189
// ------------------Input/Output methods below here-----------------------
1190
// ------------------------------------------------------------------------
1191
//
1192
 
55 rm5248 1193
 
31 rm5248 1194
/*
38 rm5248 1195
 * Class:     com_rm5248_serial_SerialInputStream
1196
 * Method:    readByte
31 rm5248 1197
 * Signature: ()I
1198
 */
38 rm5248 1199
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialInputStream_readByte
31 rm5248 1200
  (JNIEnv * env, jobject obj){
38 rm5248 1201
        int stat;
1202
        int ret_val;
34 rm5248 1203
        struct port_descriptor* desc;
38 rm5248 1204
        int get_val = 0;
1205
#ifdef _WIN32
1206
        DWORD ret = 0;
1207
        OVERLAPPED overlap = {0};
1208
        int current_available = 0;
1209
#endif 
31 rm5248 1210
 
55 rm5248 1211
        desc = get_port_descriptor( env, obj );
34 rm5248 1212
        if( desc == NULL ){
55 rm5248 1213
                return 0;
34 rm5248 1214
        }
1215
 
35 rm5248 1216
        ret_val = 0;
38 rm5248 1217
 
1218
#ifdef _WIN32
35 rm5248 1219
        {
38 rm5248 1220
                DWORD comErrors = {0};
1221
                COMSTAT portStatus = {0};
1222
                if( !ClearCommError( desc->port, &comErrors, &portStatus ) ){
1223
                        //return value zero = fail
1224
                        throw_io_exception( env, GetLastError() );
1225
                        return -1;
1226
                }else{
1227
                        current_available = portStatus.cbInQue;
1228
                }
1229
        }
1230
 
1231
        if( !current_available ){
1232
                //If nothing is currently available, wait until we get an event of some kind.
1233
                //This could be the serial lines changing state, or it could be some data
1234
                //coming into the system.
36 rm5248 1235
                overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
38 rm5248 1236
                SetCommMask( desc->port, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING );
1237
                WaitCommEvent( desc->port, &ret, &overlap );
1238
                WaitForSingleObject( overlap.hEvent, INFINITE );
1239
        }else{
1240
                //Data is available; set the RXCHAR mask so we try to read from the port
1241
                ret = EV_RXCHAR;
1242
        }
36 rm5248 1243
 
38 rm5248 1244
        if( ret & EV_RXCHAR ){
1245
                if( !ReadFile( desc->port, &ret_val, 1, &stat, &overlap) ){
36 rm5248 1246
                        throw_io_exception( env, GetLastError() );
1247
                        return -1;
1248
                }
1249
 
38 rm5248 1250
                //This is a valid byte, set our valid bit
1251
                ret_val |= ( 0x01 << 15 );
1252
        }
1253
 
1254
        //Always get the com lines no matter what       
1255
        if( GetCommModemStatus( desc->port, &get_val ) == 0 ){
1256
                throw_io_exception( env, GetLastError() );
1257
                return -1;
1258
        }
36 rm5248 1259
 
38 rm5248 1260
        if( get_val & MS_CTS_ON ){
1261
                // CTS
1262
                ret_val |= ( 0x01 << 10 );
1263
        }
36 rm5248 1264
 
38 rm5248 1265
        if( get_val & MS_DSR_ON ){
1266
                // Data Set Ready
1267
                ret_val |= ( 0x01 << 11 );
1268
        }
65 rm5248 1269
 
1270
        if( winDTR ){
1271
                ret_val |= ( 0x01 << 12 );
1272
        }
1273
 
1274
        if( winRTS ){
1275
                ret_val |= ( 0x01 << 13 );
1276
        }
36 rm5248 1277
 
38 rm5248 1278
        if( get_val & MS_RING_ON ){
1279
                // Ring Indicator
1280
                ret_val |= ( 0x01 << 14 );
1281
        }
1282
 
35 rm5248 1283
#else
63 rm5248 1284
 
1285
        //Okay, this here is going to be a bit ugly.
1286
        //The problem here is that Linux/POSIX don't specify that TIOCMIWAIT
1287
        //has to exist.  Also, the fact that if we use TIOCMIWAIT we don't
1288
        //timeout or anything.  What would be very convenient in this case
1289
        //would be to have select() return when the state changed, but
1290
        //it's not possible. :(
1291
        //Ironically, this is one case in which the Windows serial API
1292
        //is better than the POSIX way.
38 rm5248 1293
        fd_set fdset;
63 rm5248 1294
        struct timeval timeout;
1295
        int originalState;
1296
        int selectStatus;
35 rm5248 1297
 
77 rm5248 1298
        pthread_mutex_lock( &(desc->in_use) );
1299
 
63 rm5248 1300
        //first get the original state of the serial port lines
1301
        if( ioctl( desc->port, TIOCMGET, &originalState ) < 0 ){
38 rm5248 1302
                throw_io_exception( env, errno );
77 rm5248 1303
                pthread_mutex_unlock( &(desc->in_use) );
38 rm5248 1304
                return -1;
1305
        }
1306
 
63 rm5248 1307
        while( 1 ){
1308
                FD_ZERO( &fdset );
1309
                FD_SET( desc->port, &fdset );
1310
                timeout.tv_sec = 0;
77 rm5248 1311
                timeout.tv_usec = 10000; // 10,000 microseconds = 10ms
63 rm5248 1312
 
1313
                selectStatus = select( desc->port + 1, &fdset, NULL, NULL, &timeout );
1314
                if( selectStatus < 0 ){
77 rm5248 1315
                        int errval;
1316
                        if( errno == EBADF ){
1317
                                // EOF
1318
                                errval= 0;
1319
                        }else{
1320
                                throw_io_exception( env, errno );
1321
                                errval = -1;
1322
                        }
1323
                        pthread_mutex_unlock( &(desc->in_use) );
1324
                        return errval;
35 rm5248 1325
                }
63 rm5248 1326
 
1327
                if( selectStatus == 0 ){
1328
                        //This was a timeout
1329
                        if( ioctl( desc->port, TIOCMGET, &get_val ) < 0 ){
1330
                                throw_io_exception( env, errno );
77 rm5248 1331
                                pthread_mutex_unlock( &(desc->in_use) );
63 rm5248 1332
                                return -1;
1333
                        }
1334
 
1335
                        if( get_val == originalState ){
1336
                                //The state of the lines have not changed, 
1337
                                //continue on until something changes
1338
                                continue;
1339
                        }
1340
 
1341
                }
1342
 
1343
                if( FD_ISSET( desc->port, &fdset ) ){
1344
                        stat = read( desc->port, &ret_val, 1 );
1345
                        if( stat < 0 ){
1346
                                //throw new exception
1347
                                throw_io_exception( env, errno );
77 rm5248 1348
                                pthread_mutex_unlock( &(desc->in_use) );
63 rm5248 1349
                                return -1;
1350
                        }
38 rm5248 1351
 
63 rm5248 1352
                        //This is a valid byte, set our valid bit
1353
                        ret_val |= ( 0x01 << 15 );
1354
                }
1355
 
1356
                //We get to this point if we either 1. have data or
1357
                //2. our state has changed
1358
                break;
38 rm5248 1359
        }
35 rm5248 1360
 
38 rm5248 1361
        //Now that we have read in the character, let's get the serial port line state.
1362
        //If it has changed, we will fire an event in Java.
1363
        //Now, because we only read one byte at a time, we will use the lower 8 bytes to 
1364
        //return the character that we read.  The other bytes will be used to return
1365
        //information on our serial port state.
1366
        if( ioctl( desc->port, TIOCMGET, &get_val ) < 0 ){
1367
                throw_io_exception( env, errno );
77 rm5248 1368
                pthread_mutex_unlock( &(desc->in_use) );
38 rm5248 1369
                return -1;
1370
        }
35 rm5248 1371
 
38 rm5248 1372
        if( get_val & TIOCM_CD ){
1373
                // Carrier detect
1374
                ret_val |= ( 0x01 << 9 );
1375
        }
35 rm5248 1376
 
38 rm5248 1377
        if( get_val & TIOCM_CTS ){
1378
                // CTS
1379
                ret_val |= ( 0x01 << 10 );
35 rm5248 1380
        }
31 rm5248 1381
 
38 rm5248 1382
        if( get_val & TIOCM_DSR ){
1383
                // Data Set Ready
1384
                ret_val |= ( 0x01 << 11 );
8 rm5248 1385
        }
1386
 
38 rm5248 1387
        if( get_val & TIOCM_DTR ){
1388
                // Data Terminal Ready
1389
                ret_val |= ( 0x01 << 12 );
8 rm5248 1390
        }
27 rm5248 1391
 
38 rm5248 1392
        if( get_val & TIOCM_RTS ){
1393
                // Request To Send
1394
                ret_val |= ( 0x01 << 13 );
23 rm5248 1395
        }
38 rm5248 1396
 
1397
        if( get_val & TIOCM_RI ){
1398
                // Ring Indicator
1399
                ret_val |= ( 0x01 << 14 );
8 rm5248 1400
        }
38 rm5248 1401
 
77 rm5248 1402
        pthread_mutex_unlock( &(desc->in_use) );
8 rm5248 1403
#endif
38 rm5248 1404
 
8 rm5248 1405
        return ret_val;
1406
}
1407
 
1408
/*
18 rm5248 1409
 * Class:     com_rm5248_serial_SerialInputStream
8 rm5248 1410
 * Method:    getAvailable
1411
 * Signature: ()I
1412
 */
18 rm5248 1413
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialInputStream_getAvailable
8 rm5248 1414
  (JNIEnv * env, jobject obj){
1415
        jint ret_val;
1416
        struct port_descriptor* desc;
1417
 
55 rm5248 1418
        desc = get_port_descriptor( env, obj );
8 rm5248 1419
        if( desc == NULL ){
55 rm5248 1420
                return 0;
8 rm5248 1421
        }
1422
 
13 rm5248 1423
#ifdef _WIN32
23 rm5248 1424
        {
38 rm5248 1425
                DWORD comErrors = {0};
1426
                COMSTAT portStatus = {0};
1427
                if( !ClearCommError( desc->port, &comErrors, &portStatus ) ){
23 rm5248 1428
                        //return value zero = fail
27 rm5248 1429
                        throw_io_exception( env, GetLastError() );
23 rm5248 1430
                        return -1;
1431
                }else{
38 rm5248 1432
                        ret_val = portStatus.cbInQue;
23 rm5248 1433
                }
1434
        }
8 rm5248 1435
#else
1436
        if( ioctl( desc->port, FIONREAD, &ret_val ) < 0 ){
1437
                //throw new exception
27 rm5248 1438
                throw_io_exception( env, errno );
13 rm5248 1439
                return -1;
8 rm5248 1440
        }
1441
#endif
1442
        return ret_val;
1443
}
1444
 
96 rm5248 1445
/*
1446
 * Class:     com_rm5248_serial_SimpleSerialInputStream
1447
 * Method:    readByte
1448
 * Signature: ()I
1449
 */
1450
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SimpleSerialInputStream_readByte
1451
  (JNIEnv * env, jobject obj){
1452
        struct port_descriptor* desc;
1453
        jint ret_val;
1454
        int stat;
107 rm5248 1455
#ifdef _WIN32
1456
        DWORD ret = 0;
1457
        OVERLAPPED overlap = {0};
1458
        int current_available = 0;
1459
#endif 
55 rm5248 1460
 
96 rm5248 1461
        desc = get_port_descriptor( env, obj );
1462
        if( desc == NULL ){
1463
                return 0;
1464
        }
1465
 
1466
        ret_val = 0;
55 rm5248 1467
 
96 rm5248 1468
#ifdef _WIN32
107 rm5248 1469
        {
1470
                DWORD comErrors = {0};
1471
                COMSTAT portStatus = {0};
1472
                if( !ClearCommError( desc->port, &comErrors, &portStatus ) ){
1473
                        //return value zero = fail
1474
                        throw_io_exception( env, GetLastError() );
1475
                        return -1;
1476
                }else{
1477
                        current_available = portStatus.cbInQue;
1478
                }
96 rm5248 1479
        }
107 rm5248 1480
 
1481
        if( !current_available ){
1482
                //If nothing is currently available, wait until we get an event of some kind.
1483
                //This could be the serial lines changing state, or it could be some data
1484
                //coming into the system.
1485
                overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
1486
                SetCommMask( desc->port, EV_RXCHAR );
1487
                WaitCommEvent( desc->port, &ret, &overlap );
1488
                WaitForSingleObject( overlap.hEvent, INFINITE );
1489
        }else{
1490
                //Data is available; set the RXCHAR mask so we try to read from the port
1491
                ret = EV_RXCHAR;
1492
        }
1493
 
1494
        if( ret & EV_RXCHAR ){
1495
                if( !ReadFile( desc->port, &ret_val, 1, &stat, &overlap) ){
1496
                        throw_io_exception( env, GetLastError() );
1497
                        return -1;
1498
                }
1499
        }
96 rm5248 1500
#else
1501
        pthread_mutex_lock( &(desc->in_use) );
1502
        stat = read( desc->port, &ret_val, 1 );
1503
        if( stat < 0 ){
1504
                throw_io_exception( env, errno );
1505
                pthread_mutex_unlock( &(desc->in_use) );
1506
                return -1;
1507
        }
1508
        pthread_mutex_unlock( &(desc->in_use) );
1509
#endif
1510
        return ret_val;
1511
}
1512
 
8 rm5248 1513
/*
96 rm5248 1514
 * Class:     com_rm5248_serial_SimpleSerialInputStream
1515
 * Method:    getAvailable
1516
 * Signature: ()I
1517
 */
1518
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SimpleSerialInputStream_getAvailable
1519
  (JNIEnv * env, jobject obj){
1520
        //use our already-existing method to get the available bytes, it already works
1521
        return Java_com_rm5248_serial_SerialInputStream_getAvailable( env, obj );
1522
}
1523
 
1524
 
1525
/*
18 rm5248 1526
 * Class:     com_rm5248_serial_SerialOutputStream
8 rm5248 1527
 * Method:    writeByte
1528
 * Signature: (I)V
1529
 */
18 rm5248 1530
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialOutputStream_writeByte
8 rm5248 1531
  (JNIEnv * env, jobject obj, jint byte){
1532
        struct port_descriptor* desc;
1533
        char byte_write;
13 rm5248 1534
#ifdef _WIN32
1535
        DWORD bytes_written;
27 rm5248 1536
        OVERLAPPED overlap;
13 rm5248 1537
#else
1538
        int bytes_written;
1539
#endif
8 rm5248 1540
 
1541
        byte_write = byte;
1542
 
55 rm5248 1543
        desc = get_port_descriptor( env, obj );
8 rm5248 1544
        if( desc == NULL ){
1545
                return;
1546
        }
1547
 
13 rm5248 1548
#ifdef _WIN32
27 rm5248 1549
        memset( &overlap, 0, sizeof( overlap ) );
1550
        overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
1551
        if( !WriteFile( desc->port, &byte_write, sizeof( byte_write ), &bytes_written, &overlap ) ){
1552
                if( GetLastError() == ERROR_IO_PENDING ){
55 rm5248 1553
                        //Probably not an error, we're just doing this in an async fasion
1554
                        if( WaitForSingleObject( overlap.hEvent, INFINITE ) == WAIT_FAILED ){
1555
                                throw_io_exception( env, GetLastError() );
1556
                                return;
1557
                        }
27 rm5248 1558
                }else{
1559
                        throw_io_exception( env, GetLastError() );
1560
                        return;
1561
                }
13 rm5248 1562
        }
8 rm5248 1563
#else
13 rm5248 1564
        bytes_written = write( desc->port, &byte_write, sizeof( byte_write ) );
1565
        if( bytes_written < 0 ){
8 rm5248 1566
                //throw new exception
32 rm5248 1567
                throw_io_exception( env, errno );
8 rm5248 1568
                return;
1569
        }
1570
#endif
1571
}
1572
 
40 rm5248 1573
/*
1574
 * Class:     com_rm5248_serial_SerialOutputStream
1575
 * Method:    writeByteArray
1576
 * Signature: ([B)V
1577
 */
1578
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialOutputStream_writeByteArray
1579
  (JNIEnv * env, jobject obj, jbyteArray arr){
1580
        jbyte* data;
1581
        jint len;
1582
        struct port_descriptor* desc;
1583
#ifdef _WIN32
1584
        DWORD bytes_written;
1585
        OVERLAPPED overlap;
1586
#else
1587
        int bytes_written;
61 rm5248 1588
#endif /* _WIN32 */
40 rm5248 1589
 
55 rm5248 1590
        desc = get_port_descriptor( env, obj );
40 rm5248 1591
        if( desc == NULL ){
1592
                return;
1593
        }
1594
 
1595
        len = (*env)->GetArrayLength( env, arr );
1596
        data = (*env)->GetByteArrayElements(env, arr, 0);
1597
 
1598
#ifdef _WIN32
1599
        memset( &overlap, 0, sizeof( overlap ) );
1600
        overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
1601
        if( !WriteFile( desc->port, data, len, &bytes_written, &overlap ) ){
1602
                if( GetLastError() == ERROR_IO_PENDING ){
55 rm5248 1603
                        //Probably not an error, we're just doing this in an async fasion
1604
                        if( WaitForSingleObject( overlap.hEvent, INFINITE ) == WAIT_FAILED ){
1605
                                throw_io_exception( env, GetLastError() );
1606
                                return;
1607
                        }
40 rm5248 1608
                }else{
55 rm5248 1609
                        throw_io_exception( env, GetLastError() );
40 rm5248 1610
                }
1611
        }
55 rm5248 1612
 
40 rm5248 1613
#else
1614
        bytes_written = write( desc->port, data, len );
1615
        if( bytes_written < 0 ){
61 rm5248 1616
                throw_io_exception( env, errno );
40 rm5248 1617
        }
61 rm5248 1618
#endif /* _WIN32 */
40 rm5248 1619
 
1620
        (*env)->ReleaseByteArrayElements(env, arr, data, 0);
1621
}
1622
 
61 rm5248 1623
 
1624
//
1625
// ------------------------------------------------------------------------
1626
// ---------------------Static methods below here--------------------------
1627
// ------------------------------------------------------------------------
1628
//
1629
 
1630
/*
1631
 * Class:     com_rm5248_serial_SerialPort
1632
 * Method:    getMajorNativeVersion
1633
 * Signature: ()I
1634
 */
1635
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getMajorNativeVersion
1636
  (JNIEnv * env, jclass cls){
1637
        return 0;
1638
}
1639
 
1640
/*
1641
 * Class:     com_rm5248_serial_SerialPort
1642
 * Method:    getMinorNativeVersion
1643
 * Signature: ()I
1644
 */
1645
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getMinorNativeVersion
1646
  (JNIEnv * env, jclass cls){
96 rm5248 1647
        return 5;
61 rm5248 1648
}
1649
 
68 rm5248 1650
/*
1651
 * Class:     com_rm5248_serial_SerialPort
1652
 * Method:    getSerialPorts
1653
 * Signature: ()[Ljava/lang/String;
1654
 */
1655
JNIEXPORT jobjectArray JNICALL Java_com_rm5248_serial_SerialPort_getSerialPorts
1656
  (JNIEnv * env, jclass cls){
1657
        jclass stringClass;
1658
    jobjectArray array;
1659
        char** port_names;
1660
        int port_names_size;
1661
        int x;
1662
 
1663
        port_names_size = 0;
69 rm5248 1664
        port_names = malloc( sizeof( char* ) * 255 ); //max 255 serial ports
68 rm5248 1665
#ifdef _WIN32
1666
        {
1667
                //Brute force, baby!
1668
                char* port_to_open = malloc( 11 );
1669
                HANDLE* port;
1670
                for( x = 0; x <= 255; x++ ){
1671
                        _snprintf_s( port_to_open, 11, 11, "\\\\.\\COM%d", x );
1672
                        port = CreateFile( port_to_open, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0 );
1673
                        if( port != INVALID_HANDLE_VALUE ||
1674
                                ( port == INVALID_HANDLE_VALUE &&
1675
                                GetLastError() != ERROR_FILE_NOT_FOUND ) ){
1676
                                //This is a valid port
1677
                                //we could get INVALID_HANDLE_VALUE if the port is already open,
1678
                                //so make sure we check to see if it is not that value
1679
                                port_names[ port_names_size ] = malloc( 6 );
1680
                                memcpy( port_names[ port_names_size ], port_to_open + 4, 6 );
1681
                                port_names_size++;
1682
                        }
1683
                        CloseHandle( port );
1684
                }
1685
                free( port_to_open );
1686
        }
1687
#else
1688
        {
1689
                struct dirent *entry;
1690
                DIR* dir;
1691
                int fd;
69 rm5248 1692
                char* deviceName;
68 rm5248 1693
 
69 rm5248 1694
                deviceName = malloc( 100 );
1695
 
1696
                dir = opendir( "/dev/" );
1697
                if( dir == NULL ){
1698
                        throw_io_exception_message( env, "We can't open /dev." );
1699
                        free( port_names );
1700
                        free( deviceName );
1701
                        return NULL;
1702
                }
68 rm5248 1703
                while ( entry = readdir( dir ), entry != NULL) {
69 rm5248 1704
                        if( snprintf( deviceName, 100, "/dev/%s", entry->d_name ) >= 99 ){
1705
                                fprintf( stderr, "WARNING: Ignoring file %s, filename too long\n", entry->d_name );
1706
                                continue;
1707
                        }
1708
                        fd = open( deviceName, O_RDONLY );
68 rm5248 1709
                        if( fd < 0 ){
69 rm5248 1710
                                switch( errno ){
1711
                                        case EACCES:
1712
                                        case ENOMEDIUM:
1713
                                                //For some reason, I get errno 22 on my laptop
1714
                                                //when opening /dev/video0, which prints out
1715
                                                //"No such device or address"
1716
                                                //Not adding it here, because that does seem bad
1717
                                                break;
1718
                                        default:
1719
                                                perror( "open" );
1720
                                                fprintf( stderr, "ERROR: This is a very bad thing that should never happen %s:%d  errno:%d\n", __FILE__, __LINE__, errno );
1721
                                }
1722
                                close( fd );
68 rm5248 1723
                                continue;
1724
                        }
1725
 
72 rm5248 1726
                        if( isatty( fd ) && port_names_size < 255 ){
69 rm5248 1727
                                port_names[ port_names_size ] = malloc( strlen( entry->d_name ) + 6 );
1728
                                memcpy( port_names[ port_names_size ], "/dev/", 5 );
1729
                                memcpy( port_names[ port_names_size ] + 5, entry->d_name, strlen( entry->d_name ) + 1 );
68 rm5248 1730
                                port_names_size++;
1731
                        }
1732
 
1733
                        close( fd );
1734
                }
1735
                closedir( dir );
69 rm5248 1736
                free( deviceName );
68 rm5248 1737
        }
1738
#endif /* _WIN32 */
1739
 
1740
        stringClass = (*env)->FindClass(env, "java/lang/String");
1741
        array = (*env)->NewObjectArray(env, port_names_size, stringClass, 0);
1742
 
1743
        for( x = 0; x < port_names_size; x++ ){
1744
                (*env)->SetObjectArrayElement(env, array, x, (*env)->NewStringUTF( env, port_names[ x ] ) );
1745
                free( port_names[ x ] );
1746
        }
1747
 
1748
        free( port_names );
1749
 
1750
        return array;
1751
}