/*---------------------------------------------------------- I2CPort.writeByte accept: byte to write (passed as int) perform: write a single byte to the port return: none exceptions: IOException ----------------------------------------------------------*/ JNIEXPORT void JNICALL Java_gnu_io_I2CPort_writeByte( JNIEnv *env, jobject jobj, jint ji ) { unsigned char byte = (unsigned char)ji; int fd = get_java_var( env, jobj,"fd","I" ); int result; do { result=write (fd, &byte, sizeof(unsigned char)); } while (result < 0 && errno==EINTR); if(result >= 0) return; throw_java_exception( env, IO_EXCEPTION, "writeByte", strerror( errno ) ); }
JNIEXPORT void JNICALL Java_gnu_io_RS485Port_NativeEnableReceiveTimeoutThreshold(JNIEnv *env, jobject jobj, jint vtime, jint threshold, jint buffer) { int fd = get_java_var( env, jobj,"fd","I" ); struct termios ttyset; if( tcgetattr( fd, &ttyset ) < 0 ) goto fail; ttyset.c_cc[ VMIN ] = threshold; ttyset.c_cc[ VTIME ] = vtime/100; if( tcsetattr( fd, TCSANOW, &ttyset ) < 0 ) goto fail; return; fail: throw_java_exception( env, IO_EXCEPTION, "TimeoutThreshold", strerror( errno ) ); return; }
/*---------------------------------------------------------- RS485Port.writeByte accept: byte to write (passed as int) perform: write a single byte to the port return: none exceptions: IOException ----------------------------------------------------------*/ JNIEXPORT void JNICALL Java_gnu_io_RS485Port_writeByte( JNIEnv *env, jobject jobj, jint ji ) { unsigned char byte = (unsigned char)ji; int fd = get_java_var( env, jobj,"fd","I" ); int result=0,count=0; /* turn on the DTR */ ioctl(fd, TIOCMGET, &result); result |= TIOCM_DTR; ioctl(fd, TIOCMSET, &result); /* send the data */ do { result=write (fd, &byte, sizeof(unsigned char)); }while (result < 0 && errno==EINTR); if(result < 0) goto fail; /* wait for the last bit to go * see get_lsr_info in linux/driver/char/serial.c * */ #if defined(TIOCSERGETLSR) /* dima ????????? I did it in exactly the same way as in SerialImp.c */ do { result=ioctl(fd, TIOCSERGETLSR); /* FIXME this should work but its a hack */ if (result != TIOCSER_TEMT) { usleep(100); } }while(result != TIOCSER_TEMT); #endif /* TIOCSERGETLSR */ /* shut down the DTR */ ioctl(fd, TIOCMGET, &result); result &= ~TIOCM_DTR; ioctl(fd, TIOCMSET, &result); /* flush input (we dont want to get our own message */ do { result=tcflush(fd, TCIFLUSH); }while (result && errno==EINTR && count <5); if(result) goto fail; return; fail: throw_java_exception( env, IO_EXCEPTION, "writeByte", strerror( errno ) ); }
/*---------------------------------------------------------- LPRPort.isPrinterSelected accept: none perform: check if printer is selected return: JNI_TRUE if printer is selected other wise JNI_FALSE exceptions: none comments: LP_SELEC unchanged selected input, active high ----------------------------------------------------------*/ JNIEXPORT jboolean JNICALL LPRPort(isPrinterSelected)(JNIEnv *env, jobject jobj) { int fd = get_java_var( env, jobj,"fd","I" ); #if defined (__linux__) int status; ioctl(fd, LPGETSTATUS, &status); return( status & LP_SELEC ? JNI_TRUE : JNI_FALSE ); #elif defined (WIN32) return getWin32ParallelStatus( fd, PARALLEL_SELECTED); #else /* FIXME?? */ printf("ParallelImp.c LPGETSTATUS not defined\n"); return(JNI_FALSE); #endif }
/*---------------------------------------------------------- LPRPort.nativeavailable accept: none perform: find out the number of bytes available for reading return: available bytes -1 on error exceptions: none ----------------------------------------------------------*/ JNIEXPORT jint JNICALL LPRPort(nativeavailable)( JNIEnv *env, jobject jobj ) { int fd = get_java_var( env, jobj,"fd","I" ); int result; /* char message[80]; ENTER( "LPRPort:nativeavailable" ); */ /* On SCO OpenServer FIONREAD always fails for serial devices, so try ioctl FIORDCHK instead; will only tell us whether bytes are available, not how many, but better than nothing. This turns out to be true on Solaris also. taj. */ #ifdef FIORDCHK /* __unixware__ __sun__ probably others */ result = ioctl(fd, FIORDCHK, 0); #else if( ioctl( fd, FIONREAD, &result ) < 0 ) { goto fail; } #endif /* FIORDCHK */ if (result == -1) { goto fail; } if( result ) { /* sprintf(message, " nativeavailable: FIORDCHK result %d, \ errno %d\n", result , result == -1 ? errno : 0); report( message ); */ } /* LEAVE( "LPRPort:nativeavailable" ); */ return (jint)result; fail: /* report("LPRPort:nativeavailable: ioctl() failed\n"); LEAVE( "LPRPort:nativeavailable" ); */ throw_java_exception_system_msg( env, IO_EXCEPTION, "nativeavailable" ); return (jint)result; }
/*---------------------------------------------------------- LPRPort.writeArray accept: jbarray: bytes used for writing offset: offset in array to start writing count: Number of bytes to write perform: write length bytes of jbarray return: none exceptions: IOException ----------------------------------------------------------*/ JNIEXPORT void JNICALL LPRPort(writeArray)( JNIEnv *env, jobject jobj, jbyteArray jbarray, jint offset, jint count ) { #ifdef WIN32 DWORD countWritten; /* Fixme, should be a loop until all is written */ COMMTIMEOUTS timeouts; int errorCount = 0; #endif int fd = get_java_var( env, jobj,"fd","I" ); jbyte *body = (*env)->GetByteArrayElements( env, jbarray, 0 ); unsigned char *bytes = (unsigned char *)malloc( count ); int i; for( i = 0; i < count; i++ ) bytes[ i ] = body[ i + offset ]; (*env)->ReleaseByteArrayElements( env, jbarray, body, 0 ); #ifdef WIN32 /* we set a timeout because all calls are sequentiell (also with asynchron) this means that the default timeout of unlimited blocks all calls (also close and status request) if the device is down */ GetCommTimeouts( (HANDLE)fd, &timeouts ); timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 2000; /* 2000 is the min value for the default Windows NT and Windows 2000 driver */ SetCommTimeouts( (HANDLE)fd, &timeouts ); while( count > 0 ){ if(!WriteFile( (HANDLE)fd, bytes, count, &countWritten, NULL ) && countWritten == 0){ /* this are 20 * 2 seconds, in this time a printer (or other parallel device) should solv all problems like buffer full, etc */ if(errorCount++ < 20){ Sleep( 20 ); /* make a small pause to execute all other requests in all other threads */ continue; } throw_java_exception_system_msg( env, IO_EXCEPTION, "writeArray" ); break; } errorCount = 0; bytes += countWritten; count -= countWritten; } #else if( write( fd, bytes, count ) < 0 ) throw_java_exception_system_msg( env, IO_EXCEPTION, "writeArray" ); #endif free( bytes ); }
/*---------------------------------------------------------- LPRPort.isPrinterTimedOut accept: none perform: Not really sure see isPaperOut return: JNI_FALSE if the printer does not return out of paper other wise JNI_TRUE. exceptions: none comments: Is this documented right in the javadocs? not sure this is correct FIXME ----------------------------------------------------------*/ JNIEXPORT jboolean JNICALL LPRPort(isPrinterTimedOut)(JNIEnv *env, jobject jobj) { #if defined(__linux__) int fd = get_java_var( env, jobj,"fd","I" ); int status; ioctl(fd, LPGETSTATUS, &status); return( status & LP_BUSY ? JNI_TRUE : JNI_FALSE ); #endif #if defined(__FreeBSD__) printf("ParallelImp.c LPGETSTATUS not defined\n"); /* return( status & EBUSY ? JNI_TRUE : JNI_FALSE ); */ #endif return( JNI_FALSE ); }
/*---------------------------------------------------------- LPRPort.isPrinterError accept: none perform: check for printer error return: JNI_TRUE if there is an printer error otherwise JNI_FALSE exceptions: none comments: LP_ERR unchanged error input, active low ----------------------------------------------------------*/ JNIEXPORT jboolean JNICALL LPRPort(isPrinterError)(JNIEnv *env, jobject jobj) { int fd = get_java_var( env, jobj,"fd","I" ); #if defined (__linux__) int status; ioctl(fd, LPGETSTATUS, &status); return( status & LP_ERR ? JNI_TRUE : JNI_FALSE ); #elif defined (WIN32) return getWin32ParallelStatus( fd, PARALLEL_PAPER_EMPTY | PARALLEL_OFF_LINE | PARALLEL_POWER_OFF | PARALLEL_NOT_CONNECTED | PARALLEL_BUSY); #else /* FIXME?? */ printf("ParallelImp.c LPGETSTATUS not defined\n"); return(JNI_FALSE); #endif }
/*---------------------------------------------------------- I2CPort.writeArray accept: jbarray: bytes used for writing offset: offset in array to start writing count: Number of bytes to write perform: write length bytes of jbarray return: none exceptions: IOException ----------------------------------------------------------*/ JNIEXPORT void JNICALL Java_gnu_io_I2CPort_writeArray( JNIEnv *env, jobject jobj, jbyteArray jbarray, jint offset, jint count ) { int fd = get_java_var( env, jobj,"fd","I" ); int result=0,total=0,i; unsigned char *bytes = (unsigned char *)malloc( count ); jbyte *body = (*env)->GetByteArrayElements( env, jbarray, 0 ); for( i = 0; i < count; i++ ) bytes[ i ] = body[ i + offset ]; (*env)->ReleaseByteArrayElements( env, jbarray, body, 0 ); do { result=write (fd, bytes + total + offset, count - total); /* dima */ if(result >0){ total += result; } } while ((total<count)||(result < 0 && errno==EINTR)); free( bytes ); if( result < 0 ) throw_java_exception( env, IO_EXCEPTION, "writeArray", strerror( errno ) ); }
/*---------------------------------------------------------- LPRPort.isPrinterBusy accept: none perform: Check to see if the printer is printing. return: JNI_TRUE if the printer is Busy, JNI_FALSE if its idle exceptions: none comments: LP_BUSY inverted busy input, active high ----------------------------------------------------------*/ JNIEXPORT jboolean JNICALL LPRPort(isPrinterBusy)(JNIEnv *env, jobject jobj) { int fd = get_java_var( env, jobj,"fd","I" ); int status; #if defined (__linux__) ioctl(fd, LPGETSTATUS, &status); #elif defined (WIN32) return getWin32ParallelStatus( fd, PARALLEL_BUSY); #else /* FIXME?? */ printf("ParallelImp.c LPGETSTATUS not defined\n"); #endif #if defined(__linux__) return( status & LP_BUSY ? JNI_TRUE : JNI_FALSE ); #endif #if defined(__FreeBSD__) return( status & EBUSY ? JNI_TRUE : JNI_FALSE ); #endif return(JNI_FALSE); }
/*---------------------------------------------------------- I2CPort.eventLoop accept: none perform: periodically check for I2CPortEvents return: none exceptions: none comments: FIXME This is probably wrong on bsd. ----------------------------------------------------------*/ JNIEXPORT void JNICALL Java_gnu_io_I2CPort_eventLoop( JNIEnv *env, jobject jobj ) { int fd, ret, change; fd_set rfds; struct timeval tv_sleep; unsigned int mflags; #if defined(TIOCGICOUNT) struct serial_icounter_struct sis, osis; #endif /* TIOCGICOUNT */ unsigned int omflags; jmethodID method, interrupt; jboolean interrupted = 0; jclass jclazz, jthread; jclazz = (*env)->GetObjectClass( env, jobj ); fd = get_java_var(env, jobj, "fd", "I"); method = (*env)->GetMethodID( env, jclazz, "sendEvent", "(IZ)V" ); jthread = (*env)->FindClass( env, "java/lang/Thread" ); interrupt = (*env)->GetStaticMethodID( env, jthread, "interrupted", "()Z" ); /* Some multiport i2c cards do not implement TIOCGICOUNT ... */ #if defined(TIOCGICOUNT) if( ioctl( fd, TIOCGICOUNT, &osis ) < 0 ) { fprintf( stderr, "Port does not support TIOCGICOUNT events\n" ); return; } #else fprintf( stderr, "Port does not support all Hardware events\n" ); #endif /* TIOCGICOUNT */ if( ioctl( fd, TIOCMGET, &omflags) <0 ) { fprintf( stderr, "Port does not support events\n" ); return; } FD_ZERO( &rfds ); while( !interrupted ) { FD_SET( fd, &rfds ); /* Check every 1 second, or on receive data */ tv_sleep.tv_sec = 1; tv_sleep.tv_usec = 0; do { ret=select( fd + 1, &rfds, NULL, NULL, &tv_sleep ); } while (ret < 0 && errno==EINTR); if( ret < 0 ) { fprintf( stderr, "select() Failed\n" ); break; } #if defined TIOCSERGETLSR if( ioctl( fd, TIOCSERGETLSR, &change ) ) { fprintf( stderr, "TIOCSERGETLSR Failed\n" ); break; } else if( change ) { (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_OUTPUT_BUFFER_EMPTY, JNI_TRUE ); } #endif /* TIOCSERGETLSR */ #if defined(TIOCGICOUNT) /* wait for RNG, DSR, CD or CTS but not DataAvailable * The drawback here is it never times out so if someone * reads there will be no chance to try again. * This may make sense if the program does not want to * be notified of data available or errors. * ret=ioctl(fd,TIOCMIWAIT); */ if( ioctl( fd, TIOCGICOUNT, &sis ) ) { fprintf( stderr, "TIOCGICOUNT Failed\n" ); break; } while( sis.frame != osis.frame ) { (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_FE, JNI_TRUE ); osis.frame++; } while( sis.overrun != osis.overrun ) { (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_OE, JNI_TRUE ); osis.overrun++; } while( sis.parity != osis.parity ) { (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_PE, JNI_TRUE ); osis.parity++; } while( sis.brk != osis.brk ) { (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_BI, JNI_TRUE ); osis.brk++; } osis = sis; #endif /* TIOCGICOUNT */ if( ioctl( fd, TIOCMGET, &mflags ) ) { fprintf( stderr, "TIOCMGET Failed\n" ); break; } interrupted = (*env)->CallStaticBooleanMethod( env, jthread, interrupt ); /* A Portable implementation */ change = (mflags&TIOCM_CTS) - (omflags&TIOCM_CTS); if( change ) { fprintf(stderr, "Sending SPE_CTS\n"); (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_CTS, JNI_TRUE ); } change = (mflags&TIOCM_DSR) - (omflags&TIOCM_DSR); if( change ) { fprintf(stderr, "Sending SPE_DSR\n"); (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_DSR, JNI_TRUE ); } change = (mflags&TIOCM_RNG) - (omflags&TIOCM_RNG); if( change ) { fprintf(stderr, "Sending SPE_RI\n"); (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_RI, JNI_TRUE ); } change = (mflags&TIOCM_CD) - (omflags&TIOCM_CD); if( change ) { fprintf(stderr, "Sending SPE_CD\n"); (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_CD, JNI_TRUE ); } omflags = mflags; if( ioctl( fd, FIONREAD, &change ) ) { fprintf( stderr, "FIONREAD Failed\n" ); } else if( change ) { (*env)->CallVoidMethod( env, jobj, method, (jint)SPE_DATA_AVAILABLE, JNI_TRUE ); usleep(1000); /* select wont block */ } } return; }
/*---------------------------------------------------------- I2CPort.sendBreak accept: duration in milliseconds. perform: send break for actual time. not less than 0.25 seconds. exceptions: none comments: not very precise ----------------------------------------------------------*/ JNIEXPORT void JNICALL Java_gnu_io_I2CPort_sendBreak( JNIEnv *env, jobject jobj, jint duration ) { int fd = get_java_var( env, jobj,"fd","I" ); tcsendbreak( fd, (int)( duration / 250 ) ); }
/*---------------------------------------------------------- LPRPort.eventLoop accept: none perform: periodically check for ParallelPortEvents return: none exceptions: none comments: lots of work needed here. Yes its a mess. struct lp_stats { unsigned long chars; unsigned long sleeps; unsigned int maxrun; unsigned int maxwait; unsigned int meanwait; unsigned int mdev; }; ----------------------------------------------------------*/ JNIEXPORT void JNICALL LPRPort(eventLoop)( JNIEnv *env, jobject jobj ) { int fd, ret; unsigned int pflags = 0; fd_set rfds; struct timeval sleep; jboolean interrupted = 0; fd = get_java_var( env, jobj,"fd","I" ); interrupted = is_interrupted(env, jobj); FD_ZERO( &rfds ); while( !interrupted ) { FD_SET( fd, &rfds ); /* Check every 1 second, or on receive data */ sleep.tv_sec = 1; sleep.tv_usec = 0; do { ret = select( fd + 1, &rfds, NULL, NULL, &sleep ); } while (ret < 0 && errno == EINTR); if( ret < 0 ) break; interrupted = is_interrupted(env, jobj); if(interrupted) { return; } #if defined(LPGETSTATUS) ioctl( fd, LPGETSTATUS, &pflags ); #elif defined(WIN32) pflags = getWin32ParallelStatusFlags(fd); #else /* FIXME?? */ printf("ParallelImp.c LPGETSTATUS is undefined!\n"); #endif /* PAR_EV_BUFFER: PAR_EV_ERROR: */ #if defined(PARALLEL_BUSY) if (pflags & PARALLEL_BUSY) send_event( env, jobj, PAR_EV_ERROR, JNI_TRUE ); #elif defined(LP_BUSY) if (pflags&LP_BUSY) /* inverted input, active high */ send_event( env, jobj, PAR_EV_ERROR, JNI_TRUE ); #elif defined(EBUSY) if (pflags&EBUSY) /* inverted input, active high */ send_event( env, jobj, PAR_EV_ERROR, JNI_TRUE ); #endif /* EBUSY LP_BUSY */ /* FIXME this has moved into the ifdef __kernel__? Need to get the posix documentation on this. if (pflags&LP_ACK) send_event( env, jobj, PAR_EV_ERROR, JNI_TRUE ); */ #if defined (__linux__) /* unchanged input, active low */ if (pflags&LP_NOPA) /* unchanged input, active high */ send_event( env, jobj, PAR_EV_ERROR, 1 ); if (pflags&LP_SELEC) /* unchanged input, active high */ send_event( env, jobj, PAR_EV_ERROR, 1 ); if (pflags&LP_ERR) /* unchanged input, active low */ send_event( env, jobj, PAR_EV_ERROR, 1 ); #else /* FIXME?? */ printf("ParallelImp.c LPGETSTATUS is undefined!\n"); #endif usleep(1000); } return; }