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