Rev 69 | Rev 72 | 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 | |||
1613 | if( isatty( fd ) ){ |
||
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 | } |