Subversion Repositories Programming Utils

Rev

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