Subversion Repositories Programming Utils

Rev

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