Subversion Repositories Programming Utils

Rev

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