|
|
- /*-------------------------------------------------------------------------
- | rxtx is a native interface to serial ports in java.
- | Copyright 1997-2004 by Trent Jarvi taj@www.linux.org.uk
- |
- | This library is free software; you can redistribute it and/or
- | modify it under the terms of the GNU Library General Public
- | License as published by the Free Software Foundation; either
- | version 2 of the License, or (at your option) any later version.
- |
- | This library is distributed in the hope that it will be useful,
- | but WITHOUT ANY WARRANTY; without even the implied warranty of
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- | Library General Public License for more details.
- |
- | You should have received a copy of the GNU Library General Public
- | License along with this library; if not, write to the Free
- | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- --------------------------------------------------------------------------*/
- #include "gnu/io/RXTXPort.h" /* dima */
- #include "gnu/io/RXTXCommDriver.h" /* dima */
- #include "gnu/io/PortInUseException.h"
- #if defined(__MWERKS__) /* dima */
- #else /* dima */
- #include "config.h"
- #endif /* dima */
- #ifndef __LCC__
- # include <unistd.h>
- #else /* windows lcc compiler for fd_set. probably wrong */
- # include<winsock.h>
- #endif /* __LCC__ */
- #include <time.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <limits.h>
- #include <sys/stat.h>
- #ifndef WIN32
- #include <sys/ioctl.h>
- #include <sys/param.h>
- #include <sys/utsname.h>
- #include <pthread.h>
- #else
- # include <win32termios.h>
- /* FIXME returns 0 in all cases on win32
- #define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
- */
- # if !defined(S_ISCHR)
- # define S_ISCHR(m) (1)
- # endif /* S_ISCHR(m) */
- #endif /* WIN32 */
- #ifdef HAVE_ASM_TERMBITS_H
- //# include <asm/termbits.h>
- #endif /* HAVE_ASM_TERMBITS_H */
- #ifdef HAVE_TERMIOS_H
- # include <termios.h>
- #endif /* HAVE_TERMIOS_H */
- #ifdef HAVE_SIGNAL_H
- # include <signal.h>
- #endif /* HAVE_SIGNAL_H */
- #ifdef HAVE_SYS_SIGNAL_H
- # include <sys/signal.h>
- #endif /* HAVE_SYS_SIGNAL_H */
- #include <sys/types.h>
- #ifdef HAVE_SYS_TIME_H
- # include <sys/time.h>
- #endif /* HAVE_SYS_TIME_H */
- # include <fcntl.h>
- #ifdef HAVE_SYS_FCNTL_H
- # include <sys/fcntl.h>
- #endif /* HAVE_SYS_FCNTL_H */
- #ifdef HAVE_SYS_FILE_H
- # include <sys/file.h>
- #endif /* HAVE_SYS_FILE_H */
- #ifdef LFS /* File Lock Server */
- # include <sys/socket.h>
- # include <netinet/in.h>
- # include <arpa/inet.h>
- #endif /* FLS */
- #if defined(__linux__)
- # include <linux/types.h> /* fix for linux-2.3.4? kernels */
- # include <linux/serial.h>
- # include <linux/version.h>
- #endif /* __linux__ */
- #if defined(__sun__)
- # include <sys/filio.h>
- # include <sys/mkdev.h>
- #endif /* __sun__ */
- #if defined(__hpux__)
- # include <sys/modem.h>
- #endif /* __hpux__ */
- /* FIXME -- new file */
- #if defined(__APPLE__)
- # include <CoreFoundation/CoreFoundation.h>
- # include <IOKit/IOKitLib.h>
- # include <IOKit/serial/IOSerialKeys.h>
- # include <IOKit/IOBSD.h>
- #endif /* __APPLE__ */
- #ifdef __unixware__
- # include <sys/filio.h>
- #endif /* __unixware__ */
- #ifdef HAVE_PWD_H
- #include <pwd.h>
- #endif /* HAVE_PWD_H */
- #ifdef HAVE_GRP_H
- #include <grp.h>
- #endif /* HAVE_GRP_H */
- #include <math.h>
-
- extern int errno;
- #include "SerialImp.h"
- #include <gcj/cni.h>
- #include <java/lang/System.h>
- #include <java/io/PrintStream.h>
- #include <java/lang/String.h>
- #include <java/io/IOException.h>
- #include <gnu/io/UnsupportedCommOperationException.h>
- #include <java/lang/ArrayIndexOutOfBoundsException.h>
- //#define TRENT_IS_HERE_DEBUGGING_ENUMERATION
-
- struct preopened *preopened_port = NULL;
-
- #if defined(__sun__) || defined(__hpux__)
- /*----------------------------------------------------------
- cfmakeraw
-
- accept: termios to be set to raw
- perform: initializes the termios structure.
- return: int 0 on success
- exceptions: none
- comments: this is how linux cfmakeraw works.
- termios(3) manpage
- ----------------------------------------------------------*/
-
- int cfmakeraw ( struct termios *term )
- {
- ENTER( "cfmakeraw" );
- term->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- term->c_oflag &= ~OPOST;
- term->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- term->c_cflag &= ~(CSIZE|PARENB);
- term->c_cflag |= CS8;
- LEAVE( "cfmakeraw" );
- return( 0 );
- }
- #endif /* __sun__ || __hpux__ */
-
- #ifdef DEBUG_TIMING
- struct timeval snow, enow, seloop, eeloop;
- #define report_time_eventLoop( ) { \
- if ( seloop.tv_sec == eeloop.tv_sec && seloop.tv_usec == eeloop.tv_usec ) \
- { \
- gettimeofday(&eeloop, NULL); \
- seloop.tv_sec = eeloop.tv_sec; \
- seloop.tv_usec = eeloop.tv_usec; \
- printf("%8i sec : %8i usec\n", eeloop.tv_sec - seloop.tv_sec, eeloop.tv_usec - seloop.tv_usec); \
- } \
- }
- #define report_time( ) \
- { \
- struct timeval now; \
- gettimeofday(&now, NULL); \
- mexPrintf("%8s : %5i : %8i sec : %8i usec\n", __TIME__, __LINE__, now.tv_sec, now.tv_usec); \
- }
- #define report_time_start( ) \
- { \
- gettimeofday(&snow, NULL); \
- mexPrintf("%8s : %5i : %8i sec : %8i usec", __TIME__, __LINE__, snow.tv_sec, snow.tv_usec); \
- }
- #define report_time_end( ) \
- { \
- gettimeofday(&enow, NULL); \
- mexPrintf("%8i sec : %8i usec\n", enow.tv_sec - snow.tv_sec, enow.tv_sec - snow.tv_sec?snow.tv_usec-enow.tv_usec:enow.tv_usec - snow.tv_usec); \
- }
- #else
- #define report_time_eventLoop( ){};
- #define report_time( ) {}
- #define report_time_start( ) {}
- #define report_time_end( ) {}
- #endif /* DEBUG_TIMING */
-
-
- struct event_info_struct *master_index = NULL;
-
- /*----------------------------------------------------------
- RXTXPort.Initialize
-
- accept: none
- perform: Initialize the native library
- return: none
- exceptions: none
- comments: Basically this just causes rxtx to ignore signals. signal
- handlers where tried but the VM (circa 1.1) did not like it.
-
- It also allows for some sanity checks on linux boxes if DEBUG
- is enabled.
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::Initialize(
- )
- {
- #if defined DEBUG && defined(__linux__)
- struct utsname name;
- char message[80];
- #endif /* DEBUG && __linux__ */
- /* This bit of code checks to see if there is a signal handler installed
- for SIGIO, and installs SIG_IGN if there is not. This is necessary
- for the native threads jdk, but we don't want to do it with green
- threads, because it slows things down. Go figure. */
-
- /* POSIX signal handling functions */
- #if !defined(WIN32)
- struct sigaction old_action;
- sigaction(SIGIO, NULL, &old_action);
- /* green threads already has handler, no touch */
- if (old_action.sa_handler == NULL) {
- /* no handler when using native threads, set to ignore */
- struct sigaction new_action;
- sigset_t block_mask;
- sigemptyset(&block_mask);
- new_action.sa_handler = SIG_IGN;
- #ifdef SA_RESTART
- new_action.sa_flags = SA_RESTART;
- #endif /* SA_RESTART */
- new_action.sa_mask = block_mask;
- sigaction(SIGIO, &new_action, NULL);
- }
- #endif /* !WIN32 */
- ENTER( "RXTXPort:Initialize" );
- #ifdef PRERELEASE
- /* this is just for avoiding confusion while testing new libraries */
- #ifdef DEBUG_MW
- mexPrintf("RXTX Prerelease for testing Tue Feb 19 18:00:27 EST 2002\n");
- #else
- printf("RXTX Prerelease for testing Thu Feb 21 19:31:38\n");
- #endif /* DEBUG_MW */
- #endif /* PRERELEASE */
- #if DEBUG_TIMING
- gettimeofday(&seloop, NULL);
- #endif /* DEBUG_TIMING */
- #if defined(DEBUG) && defined(__linux__)
- /* Lets let people who upgraded kernels know they may have problems */
- if (uname (&name) == -1)
- {
- report( "RXTX WARNING: cannot get system name\n" );
- LEAVE( "RXTXPort:Initialize" );
- return;
- }
- if(strcmp(name.release,UTS_RELEASE)!=0)
- {
- sprintf( message, LINUX_KERNEL_VERSION_ERROR, UTS_RELEASE,
- name.release );
- report( message );
- getchar();
- }
- LEAVE( "RXTXPort:Initialize" );
- #endif /* DEBUG && __linux__ */
- }
-
- /*----------------------------------------------------------
- RXTXPort.find_preopened_ports
- accept: The device to find if preopened. ie "/dev/ttyS0"
- perform: find the filedescriptor if preopened
- return: fd
- exceptions: none
- comments: see
- RXTXPort.nativeStaticSetDSR
- RXTXPort.nativeStaticSetDTR
- RXTXPort.nativeStaticSetRTS
- RXTXPort.nativeStaticSetSerialPortParams
- This is used so people can setDTR low before calling the
- Java open().
- ----------------------------------------------------------*/
- int find_preopened_ports( const char *filename )
- {
- int fd;
- struct preopened *p = preopened_port;
-
- if( !p )
- {
- return(0);
- }
- for(;;)
- {
- if( !strcmp( p->filename, filename) )
- {
- fd = p->fd;
- if( p->prev && p->next )
- {
- p->prev->next = p->next;
- p->next->prev = p->prev;
- }
- else if ( p->prev )
- {
- p->prev->next = NULL;
- }
- else if ( p->next )
- {
- p->next->prev = NULL;
- }
- else
- {
- free( p );
- preopened_port = NULL;
- return( fd );
- }
- free( p );
- return( fd );
- }
- if( p->next )
- {
- p = p->next;
- }
- else
- {
- return(0);
- }
- }
- }
-
- /*----------------------------------------------------------
- configure_port
-
- accept: env, file descriptor
- perform: set the termios struct to sane settings and
- return: 0 on success
- exceptions: IOExcepiton
- comments: Very often people complain about not being able to get past
- this function and it turns out to be permissions on the
- device file or bios has the device disabled.
- ----------------------------------------------------------*/
-
- int configure_port( int fd )
- {
- struct termios ttyset;
-
- if( fd < 0 ) goto fail;
-
- if( tcgetattr( fd, &ttyset ) < 0 ) goto fail;
- ttyset.c_iflag = INPCK;
- ttyset.c_lflag = 0;
- ttyset.c_oflag = 0;
- ttyset.c_cflag = CREAD | CS8 | CLOCAL;
- ttyset.c_cc[ VMIN ] = 0;
- ttyset.c_cc[ VTIME ] = 0;
-
- #ifdef __FreeBSD__
- if( cfsetspeed( &ttyset, B9600 ) < 0 ) goto fail;
- #else
- if( cfsetispeed( &ttyset, B9600 ) < 0 ) goto fail;
- if( cfsetospeed( &ttyset, B9600 ) < 0 ) goto fail;
- #endif
- if( tcsetattr( fd, TCSANOW, &ttyset ) < 0 ) goto fail;
- #ifndef WIN32
- fcntl( fd, F_SETOWN, getpid() );
- #endif /* WIN32 */
- #ifdef FASYNC
- fcntl( fd, F_SETFL, FASYNC );
- #endif /* FASYNC */
-
- return 0;
-
- fail:
- return 1;
- }
-
-
- /*----------------------------------------------------------
- get_java_baudrate
-
- accept: the native speed setting
- perform: translate the native speed to a Java speed
- return: the Java speed
- exceptions: none
- comments: This is used by open() (indirectly) and
- nativeStaticGetBaudRate()
- ----------------------------------------------------------*/
- int get_java_baudrate( int native_speed )
- {
- switch( native_speed )
- {
- case B0: return 0;
- case B50: return 50;
- case B75: return 75;
- case B110: return 110;
- case B134: return 134;
- case B150: return 150;
- case B200: return 200;
- case B300: return 300;
- case B600: return 600;
- case B1200: return 1200;
- case B1800: return 1800;
- case B2400: return 2400;
- case B4800: return 4800;
- case B9600: return 9600;
- case B19200: return 19200;
- case B38400: return 38400;
- case B57600: return 57600;
- default: return -1;
- }
- }
-
- /*----------------------------------------------------------
- set_java_vars
-
- accept: fd of the preopened device
- perform: Now that the object is instatiated, set the Java variables
- to the preopened states.
- return: none
- exceptions: none
- comments: preopened refers to the fact that the serial port has
- been configured before the Java open() has been called.
- ----------------------------------------------------------*/
-
- void set_java_vars( gnu::io::RXTXPort *p,
- int fd
- )
- {
- struct termios ttyset;
- int databits = -1;
- int jparity = -1;
- int stop_bits = STOPBITS_1_5;
- int baudrate;
-
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report( "Cannot Get Serial Port Settings\n" );
- return;
- }
-
-
- switch( ttyset.c_cflag&CSIZE ) {
- case CS5: databits = JDATABITS_5; break;
- case CS6: databits = JDATABITS_6; break;
- case CS7: databits = JDATABITS_7; break;
- case CS8: databits = JDATABITS_8; break;
- }
- #ifdef CMSPAR
- switch( ttyset.c_cflag&(PARENB|PARODD|CMSPAR ) ) {
- #else
- switch( ttyset.c_cflag&(PARENB|PARODD) ) {
- #endif /* CMSPAR */
- case 0: jparity = JPARITY_NONE; break;
- case PARENB: jparity = JPARITY_EVEN; break;
- case PARENB | PARODD: jparity = JPARITY_ODD; break;
- #ifdef CMSPAR
- case PARENB | PARODD | CMSPAR: jparity = JPARITY_MARK; break;
- case PARENB | CMSPAR: jparity = JPARITY_SPACE; break;
- #endif /* CMSPAR */
- }
- switch( ttyset.c_cflag&(CSTOPB) ) {
- case 0: stop_bits = STOPBITS_1; break;
- case CSTOPB: stop_bits = STOPBITS_2; break;
- }
- /*
- dima writes:
-
- Trent, here is something I found with google:
- (freebsd list freebsd-current@freebsd.org)
-
- Andrzej Bialecki <abial@korin.warman.org.pl> asked:
- I tried to compile a piece of software, probably for Linux, and I noticed
- that we don't define CBAUD constant. I'm not sure, but I think POSIX
- defines and uses it. Should(n't) we?
-
- Bruce Evans <bde@zeta.org.au> answered:
- CBAUD is for SYSV compatibility. It is considerably inferior to POSIX's
- cf{get,set}{i,o}speed and shouldn't be provided or used.
-
- */
- #if defined(CBAUD)/* dima */
- baudrate = ttyset.c_cflag&CBAUD;
- #else
- baudrate = cfgetispeed(&ttyset);
- #endif
- p->speed = ( jint ) get_java_baudrate(baudrate) ;
- p->dataBits = ( jint ) databits ;
- p->stopBits = ( jint ) stop_bits ;
- p->parity = ( jint ) jparity ;
- }
- /*----------------------------------------------------------
- RXTXPort.open
-
- accept: The device to open. ie "/dev/ttyS0"
- perform: open the device, set the termios struct to sane settings and
- return the filedescriptor
- return: fd
- exceptions: IOExcepiton
- comments: Very often people complain about not being able to get past
- this function and it turns out to be permissions on the
- device file or bios has the device disabled.
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::open(
- java::lang::String *jstr
- )
- {
- int fd =0, i;
- int pid = -1;
- char message[80];
- report_time_start( );
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- #ifndef WIN32
- pid = getpid();
- #endif /* WIN32 */
-
- this->pid = pid;
- /*
- LOCK is one of three functions defined in SerialImp.h
-
- uucp_lock Solaris
- fhs_lock Linux
- system_does_not_lock Win32
- */
-
- ENTER( "RXTXPort:open" );
- if ( LOCK( filename, pid ) )
- {
- sprintf( message, "open: locking has failed for %s\n",
- filename );
- report( message );
- goto fail;
- }
- else
- {
- sprintf( message, "open: locking worked for %s\n", filename );
- report( message );
- }
- /* This is used so DTR can remain low on 'open()' */
- if( fd )
- {
- return (jint)fd;
- }
-
- do {
- fd=::OPEN (filename, O_RDWR | O_NOCTTY | O_NONBLOCK );
- } while (fd < 0 && errno==EINTR);
-
- if( configure_port( fd ) ) goto fail;
- sprintf( message, "open: fd returned is %i\n", fd );
- report( message );
- LEAVE( "RXTXPort:open" );
- report_time_end( );
- return (jint)fd;
-
- fail:
- LEAVE( "RXTXPort:open" );
- snprintf(message, 79, "%s %s",strerror(errno)," in open");
- throw new gnu::io::PortInUseException( JvNewStringUTF( message ) );
- //throw new PortInUseException;
- return -1;
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeClose
-
- accept: none
- perform: get the fd from the java end and close it
- return: none
- exceptions: none
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::nativeClose(
- java::lang::String *jstr
- )
- {
- int result = -1, i;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- report_time_start( );
- #ifndef WIN32
- #endif /* WIN32 */
- /*
- UNLOCK is one of three functions defined in SerialImp.h
-
- uucp_unlock Solaris
- fhs_unlock Linux
- system_does_not_unlock Win32
- */
- ENTER( "RXTXPort:nativeClose" );
- if (this->fd > 0)
- {
- do {
- result=::CLOSE (this->fd);
- } while ( result < 0 && errno == EINTR );
- UNLOCK( filename, this->pid );
- }
- LEAVE( "RXTXPort:nativeClose" );
- report_time_end( );
- return;
- }
-
- /*----------------------------------------------------------
- RXTXPort.set_port_params
-
- accept: env, fd, speed, data bits, stop bits, parity
- perform: set the serial port parameters
- return: 1 on error
- exceptions: UnsupportedCommOperationException
- comments: There is a static method and an instance method that use this
- function. The static method gets a fd first. The instance
- method can get the fd from the object.
-
- see: nativeSetSerialPortParams & nativeStaticSerialPortParams
- ----------------------------------------------------------*/
- int set_port_params(
- int fd,
- int cspeed,
- int dataBits,
- int stopBits,
- int parity
- )
- {
- struct termios ttyset;
- int result = 0;
- #if defined(TIOCGSERIAL)
- struct serial_struct sstruct;
- #endif /* TIOCGSERIAL */
-
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report( "set_port_params: Cannot Get Serial Port Settings\n" );
- return(1);
- }
-
- if( translate_data_bits( &(ttyset.c_cflag), dataBits ) )
- {
- report( "set_port_params: Invalid Data Bits Selected\n" );
- return(1);
- }
-
- if( translate_stop_bits( &(ttyset.c_cflag), stopBits ) )
- {
- report( "set_port_params: Invalid Stop Bits Selected\n" );
- return(1);
- }
-
- if( translate_parity( &(ttyset.c_cflag), parity ) )
- {
- report( "set_port_params: Invalid Parity Selected\n" );
- return(1);
- }
-
- #ifdef __FreeBSD__
- if( cfsetspeed( &ttyset, cspeed ) < 0 )
- {
- report( "set_port_params: Cannot Set Speed\n" );
- return( 1 );
- }
- #endif /* __FreeBSD__ */
- if( !cspeed )
- {
- /* hang up the modem aka drop DTR */
- /* Unix should handle this */
- /*
- mexPrintf("dropping DTR\n");
- printf("dropping DTR\n");
- */
- ioctl( fd, TIOCMGET, &result );
- result &= ~TIOCM_DTR;
- ioctl( fd, TIOCMSET, &result );
- }
- if( cfsetispeed( &ttyset, cspeed ) < 0 ||
- cfsetospeed( &ttyset, cspeed ) < 0 )
- {
- /*
- Some people need to set the baud rate to ones not defined
- in termios.h
-
- This includes some baud rates which are supported by CommAPI
- in Unix ( 14400, 28800, 128000, 256000 )
-
- If the above fails, we assume this is not a defined
- baud rate on Unix. With Win32, It is assumed the kernel
- will do this for us.
-
- The baud_base and desired speed are used to
- calculate a custom divisor.
-
- On linux the setserial man page covers this.
- */
-
- #if defined(TIOCGSERIAL)
- sstruct.custom_divisor = ( sstruct.baud_base/cspeed );
- cspeed = B38400;
- #endif /* TIOCGSERIAL */
- if( cfsetispeed( &ttyset, cspeed ) < 0 ||
- cfsetospeed( &ttyset, cspeed ) < 0 )
- {
- /* OK, we tried everything */
- report( "nativeSetSerialPortParams: Cannot Set Speed\n" );
- return( 1 );
- }
- #if defined(TIOCSSERIAL)
- /* It is assumed Win32 does this for us */
- if ( sstruct.baud_base < 1 ||
- ioctl( fd, TIOCSSERIAL, &sstruct ) < 0 )
- {
- return( 1 );
- }
- #endif /* TIOCSSERIAL */
- }
-
- if( tcsetattr( fd, TCSANOW, &ttyset ) < 0 )
- {
- report("tcsetattr returns nonzero value!\n");
- return( 1 );
- }
- return(0);
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeSetSerialPortParams
-
- accept: speed, data bits, stop bits, parity
- perform: set the serial port parameters
- return: jboolean 1 on error
- exceptions: UnsupportedCommOperationException
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeSetSerialPortParams(
- jint speed,
- jint dataBits,
- jint stopBits,
- jint parity
- )
- {
- int fd = (int) this->fd;
- int cspeed = translate_speed( speed );
-
- ENTER( "RXTXPort:nativeSetSerialPortParams" );
- report_time_start( );
-
- if (cspeed < 0 )
- {
- report(" invalid cspeed\n");
- /*
- For some reason the native exceptions are not being caught. Moving this
- to the Java side fixed the issue. taj.
- throw_java_exception( env, UNSUPPORTED_COMM_OPERATION,
- "", "BaudRate could not be set to the specified value" );
- */
- return(1);
- }
-
-
- if( set_port_params( fd, cspeed, dataBits, stopBits, parity ) )
- {
- report("set_port_params failed\n");
- LEAVE( "RXTXPort:nativeSetSerialPortParams" );
- /*
- For some reason the native exceptions are not being caught. Moving this
- to the Java side fixed the issue. taj.
- throw_java_exception( env, UNSUPPORTED_COMM_OPERATION,
- "nativeSetSerialPortParams", strerror( errno ) );
- */
- return(1);
- }
-
- LEAVE( "RXTXPort:nativeSetSerialPortParams" );
- report_time_end( );
- return(0);
- }
-
- /*----------------------------------------------------------
- translate_speed
-
- accept: speed in bits-per-second
- perform: convert bits-per-second to a speed_t constant
- return: speed_t constant
- exceptions: returns -1 and the calling method throws the exception so
- it may be caught in java.
- comments: Only the lowest level code should know about
- the magic constants.
- ----------------------------------------------------------*/
- int translate_speed(
- jint speed
- )
- {
- LEAVE( "RXTXPort:translate_speed" );
- switch( speed ) {
- case 0: return B0;
- case 50: return B50;
- case 75: return B75;
- case 110: return B110;
- case 134: return B134;
- case 150: return B150;
- case 200: return B200;
- case 300: return B300;
- case 600: return B600;
- case 1200: return B1200;
- case 1800: return B1800;
- case 2400: return B2400;
- case 4800: return B4800;
- case 9600: return B9600;
- case 19200: return B19200;
- case 38400: return B38400;
- #ifdef B57600
- case 57600: return B57600;
- #endif /* B57600 */
- #ifdef B115200
- case 115200: return B115200;
- #endif /* B115200 */
- #ifdef B230400
- case 230400: return B230400;
- #endif /* B230400 */
- #ifdef B460800
- case 460800: return B460800;
- #endif /* B460800 */
- #ifdef B14400
- case 14400: return B14400;
- #endif /* B14400 */
- #ifdef B28800
- case 28800: return B28800;
- #endif /* B28800 */
- #ifdef B128000 /* dima */
- case 128000: return B128000;
- #endif /* dima */
- #ifdef B256000 /* dima */
- case 256000: return B256000;
- #endif /* dima */
- }
-
- /* Handle custom speeds */
- if( speed >= 0 ) return speed;
- else
- {
- LEAVE( "RXTXPort:translate_speed: Error condition" );
- return -1;
- }
- }
-
- /*----------------------------------------------------------
- translate_data_bits
-
- accept: gnu.io.SerialPort.DATABITS_* constant
- perform: set proper termios c_cflag bits
- return: 1 on error
- exceptions: UnsupportedCommOperationException
- ----------------------------------------------------------*/
- int translate_data_bits(
- tcflag_t *cflag,
- jint dataBits
- )
- {
- int temp = (*cflag) & ~CSIZE;
-
- ENTER( "translate_date_bits" );
- switch( dataBits ) {
- case JDATABITS_5:
- (*cflag) = temp | CS5;
- return 0;
- case JDATABITS_6:
- (*cflag) = temp | CS6;
- return 0;
- case JDATABITS_7:
- (*cflag) = temp | CS7;
- return 0;
- case JDATABITS_8:
- (*cflag) = temp | CS8;
- return 0;
- }
-
- LEAVE( "RXTXPort:translate_date_bits" );
- /*
- For some reason the native exceptions are not being caught. Moving this
- to the Java side fixed the issue. taj.
- throw_java_exception( env, UNSUPPORTED_COMM_OPERATION,
- "", "databit value not supported" );
- */
- return 1;
- }
-
- /*----------------------------------------------------------
- translate_stop_bits
-
- accept: gnu.io.SerialPort.STOPBITS_* constant
- perform: set proper termios c_cflag bits
- return: 1 on error
- exceptions: UnsupportedCommOperationException
- comments: If you specify 5 data bits and 2 stop bits, the port will
- allegedly use 1.5 stop bits. Does anyone care?
- ----------------------------------------------------------*/
- int translate_stop_bits(
- tcflag_t *cflag,
- jint stopBits
- )
- {
- ENTER( "translate_stop_bits" );
- switch( stopBits ) {
- case STOPBITS_1:
- (*cflag) &= ~CSTOPB;
- LEAVE( "RXTXPort:translate_stop_bits" );
- return 0;
- /* ok.. lets try putting it in and see if anyone notices */
- case STOPBITS_1_5:
- if ( translate_data_bits( cflag, JDATABITS_5 ) )
- return( 1 );
- return 0;
- case STOPBITS_2:
- (*cflag) |= CSTOPB;
- LEAVE( "RXTXPort:translate_stop_bits" );
- return 0;
- }
-
- LEAVE( "RXTXPort:translate_stop_bits" );
- /*
- For some reason the native exceptions are not being caught. Moving this
- to the Java side fixed the issue. taj.
- throw_java_exception( env, UNSUPPORTED_COMM_OPERATION,
- "", "stopbit value not supported" );
- */
- return 1;
- }
- jint gnu::io::RXTXPort::nativeGetFlowControlMode(
- jint fd
- )
- {
- struct termios ttyset;
- int ret = 0;
-
- tcgetattr( fd, &ttyset );
-
- if( ttyset.c_cflag & HARDWARE_FLOW_CONTROL )
- {
- ret |= ( FLOWCONTROL_RTSCTS_IN | FLOWCONTROL_RTSCTS_OUT );
- }
- if ( ttyset.c_iflag & IXOFF )
- {
- ret |= FLOWCONTROL_XONXOFF_IN;
- }
- if ( ttyset.c_iflag & IXON )
- {
- ret |= FLOWCONTROL_XONXOFF_OUT;
- }
- return( (jint) ret );
- }
- jint gnu::io::RXTXPort::nativeGetParity(
- jint fd
- )
- {
- struct termios ttyset;
-
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report("nativeGetParity: tcgetattr failed\n");
- return( -1 );
- }
- #ifdef CMSPAR
- if ( ( ttyset.c_cflag & PARENB ) &&
- ( ttyset.c_cflag & PARODD ) &&
- ( ttyset.c_cflag & CMSPAR ) )
- {
- return( JPARITY_MARK );
- }
- else if ( ttyset.c_cflag & ( PARENB &&
- ttyset.c_cflag & CMSPAR ) )
- {
- return( JPARITY_SPACE );
- }
- #endif /* CMSPAR */
- if ( ttyset.c_cflag & PARENB &&
- ttyset.c_cflag & PARODD )
- {
- return( JPARITY_ODD );
- }
- else if ( ttyset.c_cflag & PARENB )
- {
- return( JPARITY_EVEN );
- }
- else
- {
- return( JPARITY_NONE );
- }
- }
-
- /*----------------------------------------------------------
- translate_parity
-
- accept: javax.comm.SerialPort.PARITY_* constant
- perform: set proper termios c_cflag bits
- return: 1 on error
- exceptions: UnsupportedCommOperationException
- comments: The CMSPAR bit should be used for 'mark' and 'space' parity,
- but it's not in glibc's includes. Oh well, rarely used anyway.
- ----------------------------------------------------------*/
- int translate_parity(
- tcflag_t *cflag,
- jint parity
- )
- {
- ENTER( "translate_parity" );
- #ifdef CMSPAR
- (*cflag) &= ~(PARENB | PARODD | CMSPAR );
- #endif /* CMSPAR */
- switch( parity ) {
- case JPARITY_NONE:
- LEAVE( "translate_parity" );
- return 0;
- case JPARITY_EVEN:
- (*cflag) |= PARENB;
- LEAVE( "translate_parity" );
- return 0;
- case JPARITY_ODD:
- (*cflag) |= PARENB | PARODD;
- LEAVE( "translate_parity" );
- return 0;
- #ifdef CMSPAR
- case JPARITY_MARK:
- (*cflag) |= PARENB | PARODD | CMSPAR;
- LEAVE( "translate_parity" );
- return 0;
- case JPARITY_SPACE:
- (*cflag) |= PARENB | CMSPAR;
- LEAVE( "translate_parity" );
- return 0;
- #endif /* CMSPAR */
- default:
- printf("Parity missed %i\n", (int) parity );
- }
-
- LEAVE( "translate_parity" );
- /*
- For some reason the native exceptions are not being caught. Moving this
- to the Java side fixed the issue. taj.
- throw_java_exception( env, UNSUPPORTED_COMM_OPERATION,
- "", "parity value not supported" );
- */
- return 1;
- }
- #if !defined(TIOCSERGETLSR) && !defined(WIN32)
- /*----------------------------------------------------------
- drain_loop()
-
- accept:
- perform: call tcdrain() and report an event when it succeds
- return: none
- exceptions:
- comments:
- ----------------------------------------------------------*/
- void *drain_loop( void *arg )
- {
- struct event_info_struct *eis = ( struct event_info_struct * ) arg;
- /* char msg[80]; */
- int i;
- pthread_detach( pthread_self() );
-
- for(i=0;;i++)
- {
- report_verbose("drain_loop: looping\n");
- #if defined(__sun__)
- /* FIXME: No time to test on all OS's for production */
- usleep(5000);
- #else
- usleep(1000000);
- #endif /* __sun__ */
- /*
- system_wait();
- */
- if( eis->eventloop_interrupted )
- {
- goto end;
- }
- if( tcdrain( eis->fd ) == 0 )
- {
- if( eis && eis->writing )
- {
- /*
- sprintf(msg, "drain_loop: setting OUTPUT_BUFFER_EMPTY\n" );
- report( msg );
- */
- eis->output_buffer_empty_flag = 1;
- eis->writing=false;
- }
- else
- {
- if( !eis )
- {
- goto end;
- }
- report_verbose("drain_loop: writing not set\n");
- }
- }
- else
- {
- report("drain_loop: tcdrain bad fd\n");
- goto end;
- }
- }
- end:
- report("------------------ drain_loop exiting ---------------------\n");
- eis->closing = 1;
- pthread_exit( NULL );
- return( NULL );
- }
- #endif /* !defined(TIOCSERGETLSR) && !defined(WIN32) */
- /*----------------------------------------------------------
- finalize_threads( )
-
- accept: event_info_struct used to access java and communicate with
- eventLoop().
- perform: see comments
- return: none
- exceptions: none
- comments:
- The is the pthread spawned on systems that can't access the
- LSR (Line Status Register). Without access to the LSR rxtx
- cannot detect when the output buffer is empty in the Monitor
- Thread. The solution is to return the value of write's return
- but hang around in this thread waiting for tcdrain to finish.
-
- once the drain has finished, we let the eventLoop know that the
- output buffer is empty and the Signal is sent.
- ----------------------------------------------------------*/
- void finalize_threads( struct event_info_struct *eis )
- {
- #if !defined(TIOCSERGETLSR) && !defined( WIN32 )
- /* used to shut down any remaining write threads */
-
- eis->output_buffer_empty_flag = 0;
- ENTER("finalize_threads\n");
-
- /* need to clean up again after working events */
- LEAVE("---------------- finalize_threads ---------------");
- #endif /* TIOCSERGETLSR & !WIN32 */
- }
-
- #if !defined(TIOCSERGETLSR) && !defined( WIN32 )
- static void warn_sig_abort( int signo )
- {
- char msg[80];
- sprintf( msg, "RXTX Recieved Signal %i\n", signo );
- /*
- report_error( msg );
- */
- }
- #endif /* TIOCSERGETLSR */
-
- /*----------------------------------------------------------
- init_threads( )
-
- accept: none
- perform:
- return: none
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- int init_threads( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- #if !defined(TIOCSERGETLSR) & !defined(WIN32)
- sigset_t newmask, oldmask;
- struct sigaction newaction, oldaction;
- pthread_t tid;
-
- report_time_start( );
- report("init_threads: start\n");
- sigemptyset(&newmask);
- sigaddset(&newmask, SIGCHLD);
- newaction.sa_handler = warn_sig_abort;
- sigemptyset( &newaction.sa_mask );
- #ifdef SA_INTERRUPT
- newaction.sa_flags = SA_INTERRUPT;
- #endif /* SA_INTERRUPT */
- #ifdef SA_RESTART
- newaction.sa_flags = SA_RESTART;
- #endif /* SA_RESTART */
-
- sigaction(SIGABRT, &newaction, &oldaction);
- sigaction(SIGCHLD, &newaction, &oldaction);
- sigaction(SIGALRM, &newaction, &oldaction);
- sigaction(SIGCONT, &newaction, &oldaction);
- /*
- sigaction(SIGPOLL, &newaction, &oldaction);
- sigaction(SIGTRAP, &newaction, &oldaction);
- sigaction(SIGBUS, &newaction, &oldaction);
- sigaction(SIGSEGV, &newaction, &oldaction);
- sigaction(SIGFPE, &newaction, &oldaction);
- sigaction(SIGILL, &newaction, &oldaction);
-
- sigfillset(&newmask);
- sigprocmask( SIG_SETMASK, &newmask, &oldmask );
- pthread_sigmask( SIG_BLOCK, &newmask, &oldmask );
- */
- sigprocmask( SIG_SETMASK, &newmask, &oldmask );
-
- report("init_threads: creating drain_loop\n");
- pthread_create( &tid, NULL, drain_loop, (void *) eis );
- pthread_detach( tid );
- #endif /* TIOCSERGETLSR */
- report("init_threads: set eis\n");
- p->eis = ( jint ) eis;
- report("init_threads: stop\n");
- report_time_end( );
- return( 1 );
- }
-
- /*----------------------------------------------------------
- RXTXPort.writeByte
-
- accept: byte to write (passed as int)
- jboolean interrupted (no events if true)
- perform: write a single byte to the port
- return: none
- exceptions: IOException
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::writeByte(
- jint ji,
- jboolean interrupted
- )
- {
- #ifndef TIOCSERGETLSR
- struct event_info_struct *index = master_index;
- #endif
- unsigned char byte = (unsigned char)ji;
- int fd = ( int ) this->fd;
- int result;
- char msg[80];
- #if defined ( __sun__ )
- int count;
- #endif /* __sun__ */
-
- report_time_start();
- ENTER( "RXTXPort:writeByte" );
- do {
- sprintf( msg, "writeByte %c>>\n", byte );
- report( msg );
- result=WRITE (fd, (void * ) &byte, sizeof(unsigned char));
- } while (result < 0 && errno==EINTR);
- if ( result < 0 && errno != EINTR )
- {
- snprintf( msg, 79, "%s%s", strerror( errno ), " in writeByte" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- /* On win32 I'm not sure how many bytes made it out */
- return;
- }
- /*
- This makes write for win32, glinux and Sol behave the same
- #if defined ( __sun__ )
- do {
- report_verbose( "nativeDrain: trying tcdrain\n" );
- result=tcdrain(fd);
- count++;
- } while (result && errno==EINTR && count <3);
- #endif *//* __sun __ */
- #ifndef TIOCSERGETLSR
- if( ! interrupted )
- {
- index = master_index;
- if( index )
- {
- while( index->fd != fd &&
- index->next ) index = index->next;
- }
- index->writing = 1;
- report( "writeByte: index->writing = 1" );
- }
- #endif
- sprintf( msg, "RXTXPort:writeByte %i\n", result );
- report( msg );
- LEAVE( "RXTXPort:writeByte" );
- if(result >= 0)
- {
- report_time_end();
- return;
- }
- snprintf( msg, 79, "%s%s", strerror( errno ), " in writeByte" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- }
-
- /*----------------------------------------------------------
- RXTXPort.writeArray
-
- accept: jbarray: bytes used for writing
- offset: offset in array to start writing
- count: Number of bytes to write
- jboolean interrupted (no events if true)
- perform: write length bytes of jbarray
- return: none
- exceptions: IOException
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::writeArray(
- jbyteArray jbarray,
- jint offset,
- jint count,
- jboolean interrupted
- )
- {
- #ifndef TIOCSERGETLSR
- struct event_info_struct *index = master_index;
- #endif /* TIOCSERGETLSR */
- int fd;
- int result=0,total=0;
- jbyte *out = elements( jbarray );
- char msg[80];
- #if defined ( __sun__ )
- int icount;
- #endif /* __sun__ */
- #if defined ( __sun__ )
- struct timespec retspec;
-
- retspec.tv_sec = 0;
- retspec.tv_nsec = 50000;
- #endif /* __sun__ */
- fd = ( int ) this->fd;
-
- report_time_start();
- ENTER( "writeArray" );
- /* warning Roy Rogers */
- /*
- sprintf( message, "::::RXTXPort:writeArray(%s);\n", (char *) body );
- report_verbose( message );
- */
-
- do {
- result=WRITE (fd, (void * ) ((char *) out + total + offset), count - total); /* dima */
- if(result >0){
- total += result;
- }
- report("writeArray()\n");
- } while ( ( total < count ) && ( (result < 0 && errno==EINTR ) || ( result >= 0 ) ) ) ;
- if ( result < 0 && errno != EINTR )
- {
- snprintf( msg, 79, "%s%s", strerror( errno ), " in writeArray" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- /* On win32 I'm not sure how many bytes made it out */
- return;
- }
- /*
- This makes write for win32, glinux and Sol behave the same
- #if defined ( __sun__ )
- do {
- report_verbose( "nativeDrain: trying tcdrain\n" );
- result=tcdrain(fd);
- icount++;
- } while (result && errno==EINTR && icount <3);
- #endif *//* __sun__ */
- #ifndef TIOCSERGETLSR
- if( !interrupted )
- {
- if( index )
- {
- while( index->fd != fd &&
- index->next ) index = index->next;
- }
- index->writing = 1;
- report( "writeArray: index->writing = 1" );
- }
- #endif /* TIOCSERGETLSR */
- /*
- 50 ms sleep to make sure read can get in
-
- what I think is happening here is the data writen is causing
- signals, the event loop can't select with data available
-
- I think things like BlackBox with 2 ports open are getting
- signals for both the reciever and transmitter since they
- are the same PID.
-
- Things just start spinning out of control after that.
- */
- LEAVE( "RXTXPort:writeArray" );
- report_time_end();
- return;
- fail:
- snprintf( msg, 79, "%s%s", strerror( errno ), " in writeArray" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeDrain
-
- accept: jboolean interrupted (no events if true)
- perform: wait until all data is transmitted
- return: none
- exceptions: IOException
- comments: java.io.OutputStream.flush() is equivalent to tcdrain,
- not tcflush, which throws away unsent bytes
-
- count logic added to avoid infinite loops when EINTR is
- true... Thread.yeild() was suggested.
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeDrain(
- jboolean interrupted
- )
- {
- int fd = ( int ) this->fd;
- struct event_info_struct *eis = ( struct event_info_struct * ) this->eis;
- int result, count=0;
-
- char message[80];
-
- ENTER( "SerialImp.c:drain()" );
- report_time_start( );
- do {
- report_verbose( "nativeDrain: trying tcdrain\n" );
- result=tcdrain(fd);
- count++;
- } while (result && errno==EINTR && count <3);
-
- sprintf( message, "RXTXPort:drain() returns: %i\n", result );
- report_verbose( message );
- #if defined(__sun__)
- /* FIXME: No time to test on all OS's for production */
- return( true );
- #endif /* __sun__ */
- LEAVE( "RXTXPort:drain()" );
- if( result )
- {
- snprintf( message, 79, "%s%s", strerror( errno ), " in nativeDrain" );
- throw new java::io::IOException( JvNewStringUTF( message ) );
- }
- if( interrupted ) return( false );
- #if !defined(TIOCSERGETLSR) && !defined(WIN32)
- if( eis && eis->writing )
- {
- eis->writing=false;
- eis->output_buffer_empty_flag = 0;
- }
- #endif /* !TIOCSERGETLSR !WIN32 */
- if( eis && eis->eventflags[SPE_OUTPUT_BUFFER_EMPTY] )
- {
- send_event( this, eis, SPE_OUTPUT_BUFFER_EMPTY, 1 );
- }
- report_time_end( );
- return( false );
- }
-
- /*----------------------------------------------------------
- RXTXPort.sendBreak
-
- accept: duration in milliseconds.
- perform: send break for actual time. not less than 0.25 seconds.
- exceptions: none
- comments: not very precise
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::sendBreak(
- jint duration
- )
- {
- int fd = ( int ) this->fd;
- report_time_start( );
- ENTER( "RXTXPort:sendBreak()" );
- tcsendbreak( fd, (int)( duration / 250 ) );
- report_time_end( );
- LEAVE( "RXTXPort:sendBreak()" );
- }
-
- /*----------------------------------------------------------
- RXTXPort.NativegetReceiveTimeout
-
- accept: none
- perform: get termios.c_cc[VTIME]
- return: VTIME
- comments: see NativeEnableReceiveTimeoutThreshold
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::NativegetReceiveTimeout(
- )
- {
- int fd = this->fd;
- struct termios ttyset;
- char msg[80];
-
- ENTER( "RXTXPort:nativegetRecieveTimeout()" );
- if( tcgetattr( fd, &ttyset ) < 0 ) goto fail;
- LEAVE( "RXTXPort:nativegetRecieveTimeout()" );
- return(ttyset.c_cc[ VTIME ] * 100);
- fail:
- LEAVE( "RXTXPort:nativegetRecieveTimeout()" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeGetRecieveTimeout()" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return -1;
- }
-
- /*----------------------------------------------------------
- RXTXPort.NativeisReceiveTimeoutEnabled
-
- accept: none
- perform: determine if VTIME is none 0
- return: true if VTIME > 0 else false
- comments: see NativeEnableReceiveTimeoutThreshold
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::NativeisReceiveTimeoutEnabled(
- )
- {
- int fd = this->fd;
- struct termios ttyset;
- char msg[80];
- ENTER( "RXTXPort:NativeisRecieveTimeoutEnabled()" );
- if( tcgetattr( fd, &ttyset ) < 0 ) goto fail;
- LEAVE( "RXTXPort:NativeisRecieveTimeoutEnabled()" );
- return(ttyset.c_cc[ VTIME ] > 0 ? true:false);
- fail:
- LEAVE( "RXTXPort:NativeisRecieveTimeoutEnabled()" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in isRecieveTimeoutEnabled()" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.isDSR
-
- accept: none
- perform: check status of DSR
- return: true if TIOCM_DSR is set
- false if TIOCM_DSR is not set
- exceptions: none
- comments: DSR stands for Data Set Ready
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::isDSR(
- )
- {
- unsigned int result = 0;
- int fd = this->fd;
- char message[80];
-
- ENTER( "RXTXPort:isDSR" );
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "RXTXPort:isDSR returns %i\n", result & TIOCM_DSR );
- report( message );
- LEAVE( "RXTXPort:isDSR" );
- if( result & TIOCM_DSR ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.isCD
-
- accept: none
- perform: check status of CD
- return: true if TIOCM_CD is set
- false if TIOCM_CD is not set
- exceptions: none
- comments: CD stands for Carrier Detect
- The following comment has been made...
- "well, it works, there might ofcourse be a bug, but making DCD
- permanently on fixed it for me so I don't care"
-
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::isCD(
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:isCD" );
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "RXTXPort:isCD returns %i\n", result & TIOCM_CD );
- LEAVE( "RXTXPort:isCD" );
- if( result & TIOCM_CD ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.isCTS
-
- accept: none
- perform: check status of CTS
- return: true if TIOCM_CTS is set
- false if TIOCM_CTS is not set
- exceptions: none
- comments: CTS stands for Clear To Send.
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::isCTS(
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:isCTS" );
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "RXTXPort:isCTS returns %i\n", result & TIOCM_CTS );
- report( message );
- LEAVE( "RXTXPort:isCTS" );
- if( result & TIOCM_CTS ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.isRI
-
- accept: none
- perform: check status of RI
- return: true if TIOCM_RI is set
- false if TIOCM_RI is not set
- exceptions: none
- comments: RI stands for Ring Indicator
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::isRI(
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:isRI" );
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "RXTXPort:isRI returns %i\n", result & TIOCM_RI );
- report( message );
- LEAVE( "RXTXPort:isRI" );
- if( result & TIOCM_RI ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.isRTS
-
- accept: none
- perform: check status of RTS
- return: true if TIOCM_RTS is set
- false if TIOCM_RTS is not set
- exceptions: none
- comments: tcgetattr with c_cflag CRTS_IFLOW
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::isRTS(
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:isRTS" );
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "RXTXPort:isRTS returns %i\n", result & TIOCM_RTS );
- report( message );
- LEAVE( "RXTXPort:isRTS" );
- if( result & TIOCM_RTS ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.setRTS
-
- accept: state flag to set/unset.
- perform: depends on the state flag
- if true TIOCM_RTS is set
- if false TIOCM_RTS is unset
- return: none
- exceptions: none
- comments: tcsetattr with c_cflag CRTS_IFLOW
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::setRTS(
- jboolean state
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:setRTS" );
- ioctl( fd, TIOCMGET, &result );
- if( state == true ) result |= TIOCM_RTS;
- else result &= ~TIOCM_RTS;
- ioctl( fd, TIOCMSET, &result );
- sprintf( message, "setRTS( %i )\n", state );
- report( message );
- LEAVE( "RXTXPort:setRTS" );
- return;
- }
-
- /*----------------------------------------------------------
- RXTXPort.setDSR
-
- accept: state flag to set/unset.
- perform: depends on the state flag
- if true TIOCM_DSR is set
- if false TIOCM_DSR is unset
- return: none
- exceptions: none
- comments: tcsetattr with c_cflag CRTS_IFLOW
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::setDSR(
- jboolean state
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:setDSR()" );
- ioctl( fd, TIOCMGET, &result );
-
- sprintf( message, "setDSR( %i )\n", state );
- if( state == true ) result |= TIOCM_DSR;
- else result &= ~TIOCM_DSR;
- ioctl( fd, TIOCMSET, &result );
- sprintf( message, "setDSR( %i )\n", state );
- report( message );
- LEAVE( "RXTXPort:setDSR()" );
- return;
- }
-
- /*----------------------------------------------------------
- RXTXPort.isDTR
-
- accept: none
- perform: check status of DTR
- return: true if TIOCM_DTR is set
- false if TIOCM_DTR is not set
- exceptions: none
- comments: DTR stands for Data Terminal Ready
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::isDTR(
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:isDTR" );
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "isDTR( ) returns %i\n", result& TIOCM_DTR );
- report( message );
- LEAVE( "RXTXPort:isDTR" );
- if( result & TIOCM_DTR ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.setDTR
-
- accept: new DTR state
- perform: if state is true, TIOCM_DTR is set
- if state is false, TIOCM_DTR is unset
- return: none
- exceptions: none
- comments: DTR stands for Data Terminal Ready
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::setDTR(
- jboolean state
- )
- {
- unsigned int result = 0;
- int fd = ( int ) this->fd;
- char message[80];
-
- ENTER( "RXTXPort:setDTR" );
- ioctl( fd, TIOCMGET, &result );
- if( state == true ) result |= TIOCM_DTR;
- else result &= ~TIOCM_DTR;
- ioctl( fd, TIOCMSET, &result );
- sprintf( message, "setDTR( %i )\n", state );
- report( message );
- LEAVE( "RXTXPort:setDTR" );
- return;
- }
- /*----------------------------------------------------------
- RXTXPort.static_add_filename
-
- accept: filename and fd to save
- perform: add a struct holding the info to a linked list
- return: none
- exceptions: none
- comments: the info is checked on open() if its in the list no
- changes are performed on the file on open()
-
- comments: see
- RXTXPort.nativeStaticSetDSR
- RXTXPort.nativeStaticSetDTR
- RXTXPort.nativeStaticSetRTS
- RXTXPort.nativeStaticSetSerialPortParams
- This is used so people can setDTR low before calling the
- -----------------------------------------------------------*/
-
- void static_add_filename( const char *filename, int fd)
- {
- struct preopened *newp, *p = preopened_port;
-
- newp = ( struct preopened *) malloc( sizeof( struct preopened ) );
- strcpy( newp->filename, filename );
- newp->fd = fd;
-
- if( !p )
- {
- newp->next = NULL;
- newp->prev = NULL;
- preopened_port = newp;
- return;
- }
- for(;;)
- {
- if( !strcmp( p->filename, filename) )
- {
- /* already open */
- return;
- }
- if( p->next )
- {
- p = p->next;
- }
- else
- {
- /* end of list */
- newp->next = NULL;
- newp->prev = p;
- p->next = newp;
- preopened_port = p;
- return;
- }
- }
- }
- /*----------------------------------------------------------
- RXTXPort.nativeSetBaudBase
-
- accept: The Baud Base for custom speeds
- perform: set the Baud Base
- return: 0 on success
- exceptions: Unsupported Comm Operation on systems not supporting
- TIOCGSERIAL
- comments:
- Set baud rate to 38400 before using this
- First introduced in rxtx-2.1-3
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeSetBaudBase(
- jint BaudBase
- )
- {
-
- #if defined(TIOCGSERIAL)
-
- int fd = ( int ) this->fd;
- struct serial_struct sstruct;
-
- if ( sstruct.baud_base < 1 ||
- ioctl( fd, TIOCSSERIAL, &sstruct ) < 0 )
- {
- return( true );
- }
- return( false );
- #else
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeSetBaudBase" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- return( true );
- #endif /* TIOCGSERIAL */
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeGetBaudBase
-
- accept: the Baud Base used for custom speeds
- perform:
- return: Baud Base
- exceptions: Unsupported Comm Operation on systems not supporting
- TIOCGSERIAL
- comments:
- First introduced in rxtx-2.1-3
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeGetBaudBase(
- )
- {
-
- #if defined(TIOCGSERIAL)
-
- int fd = ( int ) this->fd;
- struct serial_struct sstruct;
-
- if ( ioctl( fd, TIOCGSERIAL, &sstruct ) < 0 )
- {
- return( ( jint ) -1 );
- }
- return( ( jint ) ( sstruct.baud_base ) );
- #else
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeGetBaudBase" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- return( ( jint ) -1 );
- #endif /* TIOCGSERIAL */
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeSetDivisor
-
- accept: Divisor for custom speeds
- perform: set the Divisor for custom speeds
- return: 0 on success
- exceptions: Unsupported Comm Operation on systems not supporting
- TIOCGSERIAL
- comments:
- Set baud rate to 38400 before using this
- First introduced in rxtx-2.1-3
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeSetDivisor(
- jint Divisor
- )
- {
-
- #if defined(TIOCGSERIAL)
-
- int fd = ( int ) this->fd;
- struct serial_struct sstruct;
-
- if ( ioctl( fd, TIOCGSERIAL, &sstruct ) < 0 )
- {
- return( true );
- }
-
- if ( sstruct.custom_divisor < 1 ||
- ioctl( fd, TIOCSSERIAL, &sstruct ) < 0 )
- {
- return( true );
- }
- return( false );
- #else
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeSetDivisor" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- return( true );
- #endif /* TIOCGSERIAL */
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeGetDivisor
-
- accept: none
- perform: Find the Divisor used for custom speeds
- return: Divisor
- exceptions: Unsupported Comm Operation on systems not supporting
- TIOCGSERIAL
- comments:
- First introduced in rxtx-2.1-3
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeGetDivisor(
- )
- {
-
- #if defined(TIOCGSERIAL)
-
- int fd = ( int ) this->fd;
- struct serial_struct sstruct;
-
- if ( ioctl( fd, TIOCGSERIAL, &sstruct ) < 0 )
- {
- return( ( jint ) -1 );
- }
-
- return( ( jint ) sstruct.custom_divisor );
- #else
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeGetDivisor" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- return( ( jint ) -1 );
- #endif /* TIOCGSERIAL */
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeStaticSetDSR
-
- accept: new RTS state
- perform: if flag is true, TIOCM_DSR is set
- if flag is false, TIOCM_DSR is unset
- return: none
- exceptions: none
- comments: Set the DSR so it does not raise on the next open
- needed for some funky test boards?
-
- This is static so we can not call the open() setDSR()
- we dont have the jobject.
-
- First introduced in rxtx-1.5-9
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticSetDSR (
- jstring jstr,
- jboolean flag
- )
- {
- int fd, i, pid = -1, result;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- ENTER( "RXTXPort:nativeStaticSetDSR" );
- #ifndef WIN32
- pid = getpid();
- #endif /* WIN32 */
-
- /* Open and lock the port so nothing else changes the setting */
-
- if ( LOCK( filename, pid ) ) goto fail;;
-
- fd = find_preopened_ports( filename );
- if( !fd )
- {
- do {
- fd = ::OPEN (filename, O_RDWR | O_NOCTTY | O_NONBLOCK );
- } while (fd < 0 && errno==EINTR);
- if ( configure_port( fd ) ) goto fail;
- }
- if ( fd < 0 ) goto fail;
-
- /* raise the DSR */
-
- ioctl( fd, TIOCMGET, &result );
- if( flag == true ) result |= TIOCM_DSR;
- else result &= ~TIOCM_DSR;
- ioctl( fd, TIOCMSET, &result );
-
- /* Unlock the port. Good luck! :) */
-
- UNLOCK( filename, pid );
-
- static_add_filename( filename, fd );
-
- /* dont close the port. Its not clear if the DSR would remain high */
- LEAVE( "RXTXPort:nativeStaticSetDSR" );
- return( true );
- fail:
- LEAVE( "RXTXPort:nativeStaticSetDSR" );
- return( false );
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeStaticSetRTS
-
- accept: new RTS state
- perform: if flag is true, TIOCM_RTS is set
- if flag is false, TIOCM_RTS is unset
- return: none
- exceptions: none
- comments: Set the RTS so it does not raise on the next open
- needed for some funky test boards?
-
- This is static so we can not call the open() setDTR()
- we dont have the jobject.
-
- First introduced in rxtx-1.5-9
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticSetRTS (
- jstring jstr,
- jboolean flag
- )
- {
- int fd, i, pid = -1, result;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- ENTER( "RXTXPort:nativeStaticSetRTS" );
- #ifndef WIN32
- pid = getpid();
- #endif /* WIN32 */
-
- /* Open and lock the port so nothing else changes the setting */
-
- if ( LOCK( filename, pid ) ) goto fail;;
-
- fd = find_preopened_ports( filename );
- if( !fd )
- {
- do {
- fd = ::OPEN (filename, O_RDWR | O_NOCTTY | O_NONBLOCK );
- } while (fd < 0 && errno==EINTR);
- if ( configure_port( fd ) ) goto fail;
- }
- if ( fd < 0 ) goto fail;
-
- /* raise the RTS */
-
- ioctl( fd, TIOCMGET, &result );
- if( flag == true ) result |= TIOCM_RTS;
- else result &= ~TIOCM_RTS;
- ioctl( fd, TIOCMSET, &result );
-
- /* Unlock the port. Good luck! :) */
-
- UNLOCK( filename, pid );
-
- static_add_filename( filename, fd );
-
- /* dont close the port. Its not clear if the RTS would remain high */
- LEAVE( "RXTXPort:nativeStaticSetRTS" );
- return( true );
- fail:
- LEAVE( "RXTXPort:nativeStaticSetRTS" );
- return( false );
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeStaticSetSerialPortParams
-
- accept: string for the filename, int baudrate, int databits,
- int stopbits, int parity
- perform: set the serial port, set the params, save the fd in a linked
- list.
- return: none
- exceptions: none
- comments: Not set the speed on the next 'open'
-
- This is static so we can not call the open() setDTR()
- we dont have the jobject.
-
- First introduced in rxtx-1.5-9
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::nativeStaticSetSerialPortParams (
- jstring jstr,
- jint baudrate,
- jint dataBits,
- jint stopBits,
- jint parity
- )
- {
- int fd, i, pid = -1, cspeed = translate_speed( baudrate );
- char msg[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
-
- ENTER( "RXTXPort:nativeStaticSetSerialPortParams" );
- #ifndef WIN32
- pid = getpid();
- #endif /* WIN32 */
- /* Open and lock the port so nothing else changes the setting */
-
- if ( LOCK( filename, pid ) ) goto fail;
-
- fd = find_preopened_ports( filename );
- if( !fd )
- {
- do {
- fd = ::OPEN (filename, O_RDWR | O_NOCTTY | O_NONBLOCK );
- } while (fd < 0 && errno==EINTR);
- if ( configure_port( fd ) ) goto fail;
- }
-
- if ( fd < 0 )
- {
- LEAVE( "RXTXPort:nativeStaticSetSerialPortParams" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeStaticSetSerialPortParams" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- return;
- }
-
- if (cspeed == -1)
- {
- LEAVE( "RXTXPort:nativeStaticSetSerialPortParams" );
- snprintf( msg, 79, "%s%s", "BaudRate could not be set to the specified value", " in nativeStaticSetSerialPortParams" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- return;
- }
-
- if( set_port_params( fd, cspeed, dataBits, stopBits, parity ) )
- {
- LEAVE( "RXTXPort:nativeStaticSetSerialPortParams" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeStaticSetSerialPortParams" );
- return;
- }
-
- /* Unlock the port. Good luck! :) */
-
- UNLOCK( filename, pid );
-
- static_add_filename( filename, fd );
- /* dont close the port. */
-
- LEAVE( "RXTXPort:nativeStaticSetSerialPortParams" );
- return;
- fail:
- LEAVE( "RXTXPort:nativeStaticSetSerialPortParams" );
- return;
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeStaticSetDTR
-
- accept: new DTR state
- perform: if flag is true, TIOCM_DTR is set
- if flag is false, TIOCM_DTR is unset
- return: none
- exceptions: none
- comments: Set the DTR so it does not raise on the next open
- needed for some funky test boards?
-
- This is static so we can not call the open() setDTR()
- we dont have the jobject.
-
- First introduced in rxtx-1.5-9
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticSetDTR (
- jstring jstr,
- jboolean flag
- )
- {
- int fd, i, pid = -1, result;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- ENTER( "RXTXPort:nativeStaticSetDTR" );
- #ifndef WIN32
- pid = getpid();
- #endif /* WIN32 */
-
- /* Open and lock the port so nothing else changes the setting */
-
- if ( LOCK( filename, pid ) ) goto fail;;
-
- fd = find_preopened_ports( filename );
- if( !fd )
- {
- do {
- fd = ::OPEN (filename, O_RDWR | O_NOCTTY | O_NONBLOCK );
- } while (fd < 0 && errno==EINTR);
- if ( configure_port( fd ) ) goto fail;
- }
- if ( fd < 0 ) goto fail;
-
- /* raise the DTR */
-
- ioctl( fd, TIOCMGET, &result );
- if( flag == true ) result |= TIOCM_DTR;
- else result &= ~TIOCM_DTR;
- ioctl( fd, TIOCMSET, &result );
-
- /* Unlock the port. Good luck! :) */
-
- UNLOCK( filename, pid );
-
- static_add_filename( filename, fd );
- /* dont close the port. Its not clear if the DTR would remain high */
-
- LEAVE( "RXTXPort:nativeStaticSetDTR" );
- return( true );
- fail:
- LEAVE( "RXTXPort:nativeStaticSetDTR" );
- return( false );
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeStaticIsRTS
-
- accept: filename
- perform: check status of RTS of preopened ports (setting lines/params
- before calling the Java open()
- return: true if TIOCM_RTS is set
- false if TIOCM_RTS is not set
- exceptions: none
- comments: RTS stands for Request to Send
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticIsRTS(
- jstring jstr
- )
- {
- unsigned int result = 0;
- int i, fd;
- char message[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticIsRTS" );
- if( !fd )
- {
- /* Exception? FIXME */
- return false;
- }
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "nativeStaticIsRTS( ) returns %i\n", result& TIOCM_RTS );
- report( message );
- LEAVE( "RXTXPort:nativeStaticIsRTS" );
- if( result & TIOCM_RTS ) return true;
- else return false;
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticIsDSR
-
- accept: filename
- perform: check status of DSR of preopened ports (setting lines/params
- before calling the Java open()
- return: true if TIOCM_DSR is set
- false if TIOCM_DSR is not set
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticIsDSR(
- jstring jstr
- )
- {
- unsigned int result = 0;
- int i, fd;
- char message[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticIsDSR" );
- if( !fd )
- {
- /* Exception? FIXME */
- return false;
- }
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "nativeStaticIsDSR( ) returns %i\n", result& TIOCM_DSR );
- report( message );
- LEAVE( "RXTXPort:nativeStaticIsDSR" );
- if( result & TIOCM_DSR ) return true;
- else return false;
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticIsDTR
-
- accept: filename
- perform: check status of DTR of preopened ports (setting lines/params
- before calling the Java open()
- return: true if TIOCM_DTR is set
- false if TIOCM_DTR is not set
- exceptions: none
- comments: DTR stands for Data Terminal Ready
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticIsDTR(
- jstring jstr
- )
- {
- unsigned int result = 0;
- int i, fd;
- char message[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticIsDTR" );
- if( !fd )
- {
- /* Exception? FIXME */
- return false;
- }
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "nativeStaticIsDTR( ) returns %i\n", result& TIOCM_DTR );
- report( message );
- LEAVE( "RXTXPort:nativeStaticIsDTR" );
- if( result & TIOCM_DTR ) return true;
- else return false;
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticIsCD
-
- accept: filename
- perform: check status of CD of preopened ports (setting lines/params
- before calling the Java open()
- return: true if TIOCM_CD is set
- false if TIOCM_CD is not set
- exceptions: none
- comments: CD stands for carrier detect
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticIsCD(
- jstring jstr
- )
- {
- unsigned int result = 0;
- int i, fd;
- char message[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticIsCD" );
- if( !fd )
- {
- /* Exception? FIXME */
- return false;
- }
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "nativeStaticIsCD( ) returns %i\n", result& TIOCM_CD );
- report( message );
- LEAVE( "RXTXPort:nativeStaticIsCD" );
- if( result & TIOCM_CD ) return true;
- else return false;
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticIsCTS
-
- accept: filename
- perform: check status of CTS of preopened ports (setting lines/params
- before calling the Java open()
- return: true if TIOCM_CTS is set
- false if TIOCM_CTS is not set
- exceptions: none
- comments: CTS stands for Clear To Send
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticIsCTS(
- jstring jstr
- )
- {
- unsigned int result = 0;
- int i, fd;
- char message[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticIsCTS" );
- if( !fd )
- {
- /* Exception? FIXME */
- return false;
- }
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "nativeStaticIsCTS( ) returns %i\n", result& TIOCM_CTS );
- report( message );
- LEAVE( "RXTXPort:nativeStaticIsCTS" );
- if( result & TIOCM_CTS ) return true;
- else return false;
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticIsRI
-
- accept: filename
- perform: check status of RI of preopened ports (setting lines/params
- before calling the Java open()
- return: true if TIOCM_RI is set
- false if TIOCM_RI is not set
- exceptions: none
- comments: RI stands for carrier detect
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeStaticIsRI(
- jstring jstr
- )
- {
- unsigned int result = 0;
- int i, fd;
- char message[80];
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticIsRI" );
- if( !fd )
- {
- /* Exception? FIXME */
- return false;
- }
- ioctl( fd, TIOCMGET, &result );
- sprintf( message, "nativeStaticRI( ) returns %i\n", result& TIOCM_RI );
- report( message );
- LEAVE( "RXTXPort:nativeStaticIsRI" );
- if( result & TIOCM_RI ) return true;
- else return false;
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeStaticGetBaudRate
-
- accept: filename
- perform: find the baud rate (not all buads are handled yet)
- return: return the baud rate or -1 if not supported yet.
- exceptions:
- comments: simple test for preopened ports
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeStaticGetBaudRate(
- jstring jstr
- )
- {
- int i, fd;
- struct termios ttyset;
- int baudrate;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticGetBaudRate" );
- if( !fd )
- {
- /* Exception? FIXME */
- return -1;
- }
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report( "nativeStaticGetBaudRate: Cannot Get Serial Port Settings\n" );
- return(-1);
- }
- /*
- dima writes:
-
- Trent, here is something I found with google:
- (freebsd list freebsd-current@freebsd.org)
-
- Andrzej Bialecki <abial@korin.warman.org.pl> asked:
- I tried to compile a piece of software, probably for Linux, and I noticed
- that we don't define CBAUD constant. I'm not sure, but I think POSIX
- defines and uses it. Should(n't) we?
-
- Bruce Evans <bde@zeta.org.au> answered:
- CBAUD is for SYSV compatibility. It is considerably inferior to POSIX's
- cf{get,set}{i,o}speed and shouldn't be provided or used.
-
- */
- #if defined(CBAUD)/* dima */
- baudrate = ttyset.c_cflag&CBAUD;
- #else
- if(cfgetispeed(&ttyset) != cfgetospeed(&ttyset)) return -1;
- baudrate = cfgetispeed(&ttyset);
- #endif
- return( get_java_baudrate(baudrate) );
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticGetDataBits
-
- accept: filename
- perform: find the data bits (not all buads are handled yet)
- return: return the data bits
- exceptions:
- comments: simple test for preopened ports
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeStaticGetDataBits(
- jstring jstr
- )
- {
- int i, fd;
- struct termios ttyset;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticGetDataBits" );
- if( !fd )
- {
- /* Exception? FIXME */
- return -1;
- }
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report( "nativeStaticGetDataBits: Cannot Get Serial Port Settings\n" );
- return(-1);
- }
- switch( ttyset.c_cflag&CSIZE ) {
- case CS5: return JDATABITS_5;
- case CS6: return JDATABITS_6;
- case CS7: return JDATABITS_7;
- case CS8: return JDATABITS_8;
- default: return(-1);
- }
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticGetParity
-
- accept: filename
- perform: find the parity
- return: return the parity
- exceptions:
- comments: simple test for preopened ports
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeStaticGetParity(
- jstring jstr
- )
- {
- int i, fd;
- struct termios ttyset;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- fd = find_preopened_ports( filename );
-
- ENTER( "RXTXPort:nativeStaticGetParity" );
- if( !fd )
- {
- /* Exception? FIXME */
- return -1;
- }
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report( "nativeStaticGetParity: Cannot Get Serial Port Settings\n" );
- return(-1);
- }
- #ifdef CMSPAR
- switch( ttyset.c_cflag&(PARENB|PARODD|CMSPAR ) ) {
- #else
- switch( ttyset.c_cflag&(PARENB|PARODD) ) {
- #endif /* CMSPAR */
- case 0: return JPARITY_NONE;
- case PARENB: return JPARITY_EVEN;
- case PARENB | PARODD: return JPARITY_ODD;
- #ifdef CMSPAR
- case PARENB | PARODD | CMSPAR: return JPARITY_MARK;
- case PARENB | CMSPAR: return JPARITY_SPACE;
- #endif /* CMSPAR */
- default: return(-1);
- }
- }
- /*----------------------------------------------------------
- RXTXPort.nativeStaticGetStopBits
-
- accept: filename
- perform: find the stop bits
- return: return the stop bits
- exceptions:
- comments: simple test for preopened ports
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeStaticGetStopBits(
- jstring jstr
- )
- {
- int i, fd;
- struct termios ttyset;
- char filename[80];
- fd = find_preopened_ports( filename );
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- ENTER( "RXTXPort:nativeStaticGetStopBits" );
- if( !fd )
- {
- /* Exception? FIXME */
- return -1;
- }
- if( tcgetattr( fd, &ttyset ) < 0 )
- {
- report( "nativeStaticGetStopBits: Cannot Get Serial Port Settings\n" );
- return(-1);
- }
- switch( ttyset.c_cflag&(CSTOPB) ) {
- case 0: return STOPBITS_1;
- case CSTOPB: return STOPBITS_2;
- default: return STOPBITS_1_5;
- }
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeGetParityErrorChar
-
- accept: -
- perform: check the ParityErrorChar
- return: The ParityErrorChar as an jbyte.
- exceptions: UnsupportedCommOperationException if not implemented
- comments: It appears the Parity char is usually \0. The windows
- API allows for this to be changed. I cant find may
- examples of this being done. Maybe for a reason.
-
- Use a direct call to the termios file until we find a
- solution.
- ----------------------------------------------------------*/
- jbyte gnu::io::RXTXPort::nativeGetParityErrorChar(
- )
- {
- unsigned int result = 0;
-
- ENTER( "nativeGetParityErrorChar" );
- #ifdef WIN32
- result = ( jbyte ) termiosGetParityErrorChar(
- this->fd );
- #else
- /*
- arg! I cant find a way to change it from \0 in Linux. I think
- the frame and parity error characters are hardcoded.
- */
- result = ( jint ) '\0';
-
- #endif /* WIN32 */
- LEAVE( "nativeGetParityErrorChar" );
- return( ( jbyte ) result );
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeGetEndOfInputChar
-
- accept: -
- perform: check the EndOf InputChar
- return: the EndOfInputChar as an jbyte. -1 on error
- exceptions: UnsupportedCommOperationException if not implemented
- comments:
- ----------------------------------------------------------*/
- jbyte gnu::io::RXTXPort::nativeGetEndOfInputChar(
- )
- {
- int fd = ( int ) this->fd;
- struct termios ttyset;
-
- ENTER( "nativeGetEndOfInputChar" );
- if( tcgetattr( fd, &ttyset ) < 0 ) goto fail;
- LEAVE( "nativeGetEndOfInputChar" );
- return( (jbyte) ttyset.c_cc[VEOF] );
- fail:
- LEAVE( "nativeGetEndOfInputChar" );
- report( "nativeGetEndOfInputChar failed\n" );
- return( ( jbyte ) -1 );
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeSetParityErrorChar
-
- accept: the ParityArrorCharacter as an int.
- perform: Set the ParityErrorChar
- return: true on success
- exceptions: UnsupportedCommOperationException if not implemented
- comments: It appears the Parity char is usually \0. The windows
- API allows for this to be changed. I cant find may
- examples of this being done. Maybe for a reason.
-
- Use a direct call to the termios file until we find a
- solution.
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeSetParityErrorChar(
- jbyte value
- )
- {
-
- char msg[80];
- #ifdef WIN32
- int fd = ( int ) this->fd;
- ENTER( "nativeSetParityErrorChar" );
- termiosSetParityError( fd, ( char ) value );
- LEAVE( "nativeSetParityErrorChar" );
- return( true );
- #else
- ENTER( "nativeSetParityErrorChar" );
- /*
- arg! I cant find a way to change it from \0 in Linux. I think
- the frame and parity error characters are hardcoded.
- */
-
- snprintf( msg, 79, "%s%s", strerror( errno ), " in setParityErrorChar()" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- LEAVE( "nativeSetParityErrorChar" );
- return( false );
- #endif /* WIN32 */
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeSetEndOfInputChar
-
- accept: The EndOfInputChar as an int
- perform: set the EndOfInputChar
- return: true on success
- exceptions: UnsupportedCommOperationException if not implemented
- comments: This may cause troubles on Windows.
- Lets give it a shot and see what happens.
-
- See termios.c for the windows bits.
-
- EofChar = val;
- fBinary = false; winapi docs say always use true. ?
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXPort::nativeSetEndOfInputChar(
- jbyte value
- )
- {
- int fd = ( int ) this->fd;
- struct termios ttyset;
- char msg[80];
-
- ENTER( "nativeSetEndOfInputChar" );
- if( tcgetattr( fd, &ttyset ) < 0 ) goto fail;
- ttyset.c_cc[VEOF] = ( char ) value;
- if( tcsetattr( fd, TCSANOW, &ttyset ) < 0 ) goto fail;
- LEAVE( "nativeSetEndOfInputChar" );
- return( true );
- fail:
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeSetEndOfInputChar" );
- throw new gnu::io::UnsupportedCommOperationException( JvNewStringUTF( msg ) );
- report( "nativeSetEndOfInputChar failed\n" );
- LEAVE( "nativeSetEndOfInputChar" );
- return( false );
- }
-
- #ifndef WIN32
- long
- GetTickCount()
- {
- /* return milliseconds */
- struct timeval now;
-
- gettimeofday(&now, NULL);
- report_verbose("gettimeofday\n");
-
- #ifdef __QNX__
- return ( ( now.tv_sec * 1000 + now.tv_usec / 1000 ) );
- #else
- return ( ( now.tv_sec * 1000) + ( long ) ceil( ( double ) now.tv_usec / 1000 ) );
- #endif /* __QNX__ */
- }
-
- #endif /* !WIN32 */
-
- /*----------------------------------------------------------
- read_byte_array
-
- accept: int fd file descriptor to read from
- unsigned char *buffer buffer to read data into
- int length number of bytes to read
- int timeout milliseconds to wait before returning
- perform: read bytes from the port into a buffer
- return: status of read
- -1 fail (IOException)
- 0 timeout
- >0 number of bytes read
- comments: According to the Communications API spec, a receive threshold
- of 1 is the same as having the threshold disabled.
-
- The nuts and bolts are documented in
- NativeEnableReceiveTimeoutThreshold()
- ----------------------------------------------------------*/
-
- int read_byte_array(
- int fd,
- unsigned char *buffer,
- int length,
- int timeout
- )
- {
- int ret, left, bytes = 0;
- long timeLeft, now = 0, start = 0;
- char msg[80];
- struct timeval tv, *tvP;
- fd_set rset;
- /* TRENT */
- int count = 0;
- sigset_t sigpwr_mask;
-
- // init the sigset for blocking SIGPWR + SIGXCPU
- sigemptyset(&sigpwr_mask);
- sigaddset(&sigpwr_mask, SIGPWR);
- sigaddset(&sigpwr_mask, SIGXCPU);
-
- report_time_start();
- ENTER( "read_byte_array" );
- sprintf(msg, "read_byte_array requests %i\n", length);
- report( msg );
- left = length;
- if (timeout >= 0)
- start = GetTickCount();
- while( bytes < length && count++ < 20 );
- {
- if (timeout >= 0) {
- now = GetTickCount();
- if ( now-start >= timeout )
- return bytes;
- }
-
- FD_ZERO(&rset);
- FD_SET(fd, &rset);
-
- if (timeout >= 0){
- timeLeft = timeout - (now - start);
- tv.tv_sec = timeLeft / 1000;
- tv.tv_usec = 1000 * ( timeLeft % 1000 );
- tvP = &tv;
- }
- else{
- tvP = NULL;
- }
-
- // ignore SIGPWR + SIGXCPU during SELECT as gcj GC uses these signals
- sigprocmask(SIG_BLOCK, &sigpwr_mask, NULL);
- do {
- ret = SELECT(fd + 1, &rset, NULL, NULL, tvP);
- } while ( ret < 0 && errno == EINTR );
- sigprocmask(SIG_UNBLOCK, &sigpwr_mask, NULL);
- if (ret == -1){
- report( "read_byte_array: select returned -1\n" );
- LEAVE( "read_byte_array" );
- return -1;
- }
- else if (ret > 0){
- if ((ret = READ( fd, buffer + bytes, left )) < 0 ){
- if (errno != EINTR && errno != EAGAIN){
- report( "read_byte_array: read returned -1\n" );
- LEAVE( "read_byte_array" );
- return -1;
- }
- }
- else if ( ret ) {
- bytes += ret;
- left -= ret;
- }
- /*
- The only thing that is bugging me with the new
- version is the CPU usage when reading on the serial port. I
- looked at it today and find a quick fix. It doesn't seems to
- affect the performance for our apps (I mean in a negative way,
- cause the CPU is back to normal, near 0-5%). All I did is add
- a usleep in the reading function.
-
- Nicolas <ripley@8d.com>
- */
- else {
- //usleep(10);
- usleep(1000);
- }
- }
- }
- /*
- if( count > 19 )
- {
- throw_java_exception( env, IO_EXCEPTION, "read_byte_array",
- "No data available" );
- }
- */
-
- //*(buffer+bytes) = 0;
- sprintf(msg, "read_byte_array returns %i\n", bytes);
- report( msg );
- LEAVE( "read_byte_array" );
- report_time_end();
- return bytes;
- }
-
- /*----------------------------------------------------------
- NativeEnableReceiveTimeoutThreshold
- accept: int threshold, int vtime,int buffer
- perform: Set c_cc->VMIN to threshold and c_cc=>VTIME to vtime
- return: void
- exceptions: IOException
- comments: This is actually all handled in read with select in
- canonical input mode.
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::NativeEnableReceiveTimeoutThreshold(
- jint vtime,
- jint threshold,
- jint buffer
- )
- {
- int fd = ( int ) this->fd;
- struct termios ttyset;
- int timeout;
- char msg[80];
-
- if (vtime < 0){
- timeout = 0;
- }
- else if (vtime == 0){
- timeout = 1;
- }
- else{
- timeout = vtime;
- }
-
- ENTER( "RXTXPort:NativeEnableRecieveTimeoutThreshold" );
- if( tcgetattr( fd, &ttyset ) < 0 ) goto fail;
- /* TESTING ttyset.c_cc[ VMIN ] = threshold; */
- ttyset.c_cc[ VMIN ] = 0;
- ttyset.c_cc[ VTIME ] = timeout/100;
- if( tcsetattr( fd, TCSANOW, &ttyset ) < 0 ) goto fail;
-
- LEAVE( "RXTXPort:NativeEnableRecieveTimeoutThreshold" );
- return;
- fail:
- LEAVE( "RXTXPort:NativeEnableRecieveTimeoutThreshold" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in TimeoutThreshold" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return;
- }
-
- /*----------------------------------------------------------
- RXTXPort.readByte
-
- accept: none
- perform: Read a single byte from the port. Block unless an exeption
- is thrown, or end of stream.
- return: The byte read
- exceptions: IOException
- comments:
-
- On Fri, 30 Aug 2002, Bill Smith wrote:
-
- I agree, the documentation isn't the best. No surprises there.
-
- I did do a test using the sun/win32 comm driver with read() and retrieve
- timeout enabled. It blocked until the timeout expired, then returned a -1.
- This seems to jive with the way I'm reading it which is the javax.comm
- comments regarding read (in the CommPort.getInputStream stuff)
- extends/overrides
- the documentation for java.io.InputStream.
-
- This is the same behavior that the Windriver driver for vxworks exhibits.
-
- On Fri, 30 Aug 2002, Bill Smith wrote:
-
- > Hi Trent,
- >
- > I have a couple of questions/comments.
- >
- > 1) I noticed in the thread last night and in the code changes this morning that you
- > now have readByte() (which is called from the input stream read(), to block
- > forever. I pulled the following info from the javax.comm doc for the CommPort class in
- > getInputStream().
- >
- > The way I interpret that is that read() just like read(byte[]), and read(byte[], int, int),
- > show only block indefinitely if timeout is disabled. The sun implementation for win32 (as
- > well as the one we have for vxworks) returns a -1 when it times out.
- >
-
- Doing what Sun does is going to the least hassle. The documentation was a
- little unclear to me. I assume this is the CommPort.getInputStream
- comment that you mention
-
- The read behaviour of the input stream returned by getInputStream
- depends on combination of the threshold and timeout values. The
- possible behaviours are described in the table below: ...
-
- But InputStream is where read(byte) is documented
- http://java.sun.com/j2se/1.3/docs/api/java/io/InputStream.html#read()
-
- Reads the next byte of data from the input stream. The value byte
- is returned as an int in the range 0 to 255. If no byte is
- available because the end of the stream has been reached, the value
- -1 is returned. This method blocks until input data is
- available, the end of the stream is detected, or an exception is
- thrown
-
- If you are sure commapi is doing a timeout and returning -1, I can change
- it back and document the issue.
-
- Because I often grep my own mailbox for details, I'm going to add
- these two comments also:
-
- public int read(byte[] b)
- )
- http://java.sun.com/j2se/1.3/docs/api/java/io/InputStream.html#read(byte[])
-
- Reads some number of bytes from the input stream and stores them
- into the buffer array b. The number of bytes actually read is
- returned as an integer. This method blocks until input data is
- available, end of file is detected, or an exception is thrown.
-
- If b is null, a NullPointerException is thrown. If the length of b
- is zero, then no bytes are read and 0 is returned; otherwise,
- there is an attempt to read at least one byte. If no byte is
- available because the stream is at end of file, the value -1 is
- returned; otherwise, at least one byte is read and stored into b.
-
- So read(byte[] b) is documented as blocking for the first byte.
-
- public int read(byte[] b,int off,int len)
- http://java.sun.com/j2se/1.3/docs/api/java/io/InputStream.html#read(byte[],
- int, int)
-
- Reads up to len bytes of data from the input stream into an array of
- bytes. An attempt is made to read as many as len bytes, but a
- smaller number may be read, possibly zero. The number of bytes
- actually read is returned as an integer.
-
- Which makes sense with the timeout documentation.
-
- <snip>threshold comment I'll look at that next. I thought those changes
- where in the ifdefed code. I'll take a second look and reply.
-
- >
- > Thoughts? Comments?
- >
- > Bill
- >
- > ----------------------
- >
- > public abstract InputStream getInputStream() throws IOException
- >
- >
- > Returns an input stream. This is the only way to receive data from the
- communications
- > port. If the port is unidirectional and doesn't support receiving data, then
- > getInputStream returns null.
- >
- > The read behaviour of the input stream returned by getInputStream depends on
- > combination of the threshold and timeout values. The possible behaviours are
- > described in the table below:
- >
- >
- > Threshold Timeout Read Buffer Read Behaviour
- > State Value State Value Size
- >
- -----------------------------------------------------------------------------------
- > disabled - disabled - n bytes block until any data is available
- >
- > enabled m bytes disabled - n bytes block until min(m,n) bytes are available
- >
- > disabled - enabled x ms n bytes block for x ms or
- until any data is available
- >
- > enabled m bytes enabled x ms n bytes block for x ms or
- until min(m,n) bytes are available
- >
- > Returns: InputStream object that can be used to read from the port
- >
- > Throws: IOException if an I/O error occurred
-
-
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::readByte(
- )
- {
- int bytes;
- unsigned char buffer[ 1 ];
- int fd = ( int ) this->fd;
- int timeout = ( int ) this->timeout;
- char msg[80];
-
- ENTER( "RXTXPort:readByte" );
- report_time_start( );
- bytes = read_byte_array( fd, buffer, 1, timeout );
- if( bytes < 0 ) {
- LEAVE( "RXTXPort:readByte" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in readByte" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return -1;
- }
- LEAVE( "RXTXPort:readByte" );
- sprintf( msg, "readByte return(%i)\n", bytes ? buffer[ 0 ] : -1 );
- report( msg );
- report_time_end( );
- return (bytes ? (jint)buffer[ 0 ] : -1);
- }
-
- /*----------------------------------------------------------
- RXTXPort.readArray
-
- accept: offset (offset to start storing data in the jbarray) and
- Length (bytes to read)
- perform: read bytes from the port into a byte array
- return: bytes read on success
- 0 on read timeout
- exceptions: IOException
- comments: throws ArrayIndexOutOfBoundsException if asked to
- read more than SSIZE_MAX bytes
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::readArray(
- jbyteArray jbarray,
- jint offset,
- jint length
- )
- {
- int bytes;
- char msg[80];
- int fd = ( int ) this->fd;
- int timeout = ( int ) this->timeout;
- jbyte *in = elements( jbarray ) + offset;
-
- ENTER( "readArray" );
- report_time_start( );
- if( length > SSIZE_MAX || length < 0 ) {
- report( "RXTXPort:readArray length > SSIZE_MAX" );
- LEAVE( "RXTXPort:readArray" );
- snprintf( msg, 79, "%s%s", "Invalid length", " in readArray" );
- throw new java::lang::ArrayIndexOutOfBoundsException( JvNewStringUTF( msg ) );
- return -1;
- }
- bytes = read_byte_array( fd, (unsigned char *) in, length, timeout );/* dima */
- if( bytes < 0 ) {
- report( "RXTXPort:readArray bytes < 0" );
- LEAVE( "RXTXPort:readArray" );
- snprintf( msg, 79, "%s%s", strerror( errno ), " in readArray" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return -1;
- }
- sprintf( msg, "RXTXPort:readArray: %i %i\n", (int) length, bytes);
- report( msg );
- report_time_end( );
-
- LEAVE( "RXTXPort:readArray" );
- return (bytes);
- }
-
- /*----------------------------------------------------------
- RXTXPort.nativeavailable
-
- accept: none
- perform: find out the number of bytes available for reading
- return: available bytes
- -1 on error
- exceptions: none
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::nativeavailable(
- )
- {
- int fd = ( int ) this->fd;
- int result;
- char msg[80];
-
- /*
- ENTER( "RXTXPort: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 */
- sprintf(msg, " nativeavailable: FIORDCHK result %d, \
- errno %d\n", result , result == -1 ? errno : 0);
- report_verbose( msg );
- if (result == -1) {
- goto fail;
- }
- if( result )
- {
- sprintf(msg, " nativeavailable: FIORDCHK result %d, \
- errno %d\n", result , result == -1 ? errno : 0);
- report( msg );
- }
- /*
- LEAVE( "RXTXPort:nativeavailable" );
- */
- return (jint)result;
- fail:
- report("RXTXPort:nativeavailable: ioctl() failed\n");
- /*
- LEAVE( "RXTXPort:nativeavailable" );
- */
- snprintf( msg, 79, "%s%s", strerror( errno ), " in nativeavailable" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return (jint)result;
- }
-
- /*----------------------------------------------------------
- RXTXPort.setflowcontrol
-
- accept: flowmode
- FLOWCONTROL_NONE none
- FLOWCONTROL_RTSCTS_IN hardware flow control
- FLOWCONTROL_RTSCTS_OUT ""
- FLOWCONTROL_XONXOFF_IN input software flow control
- FLOWCONTROL_XONXOFF_OUT output software flow control
- perform: set flow control to flowmode
- return: none
- exceptions: UnsupportedCommOperationException
- comments: there is no differentiation between input and output hardware
- flow control
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::setflowcontrol(
- jint flowmode
- )
- {
- struct termios ttyset;
- int fd = ( int ) this->fd;
- char msg[80];
-
- ENTER( "RXTXPort:setflowcontrol" );
- if( tcgetattr( fd, &ttyset ) ) goto fail;
-
- if ( flowmode & ( FLOWCONTROL_RTSCTS_IN | FLOWCONTROL_RTSCTS_OUT ) )
- {
- ttyset.c_cflag |= HARDWARE_FLOW_CONTROL;
- }
- else ttyset.c_cflag &= ~HARDWARE_FLOW_CONTROL;
-
- ttyset.c_iflag &= ~IXANY;
-
- if ( flowmode & FLOWCONTROL_XONXOFF_IN )
- {
- ttyset.c_iflag |= IXOFF;
- }
- else ttyset.c_iflag &= ~IXOFF;
-
- if ( flowmode & FLOWCONTROL_XONXOFF_OUT )
- {
-
- ttyset.c_iflag |= IXON;
- }
- else ttyset.c_iflag &= ~IXON;
- /* TRENT */
- if( tcsetattr( fd, TCSANOW, &ttyset ) ) goto fail;
- LEAVE( "RXTXPort:setflowcontrol" );
- return;
- fail:
- LEAVE( "RXTXPort:setflowcontrol" );
- snprintf( msg, 79, "%s%s", "flow control type not supported", " in setflowcontrol" );
- throw new java::io::IOException( JvNewStringUTF( msg ) );
- return;
- }
-
- /*----------------------------------------------------------
- unlock_monitor_thread
-
- accept: event_info_struct
- perform: unlock the monitor thread so event notification can start.
- return: none
- exceptions: none
- comments: Events can be missed otherwise.
- ----------------------------------------------------------*/
-
- void unlock_monitor_thread( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- p->MonitorThreadLock = false;
- }
-
- /*----------------------------------------------------------
- check_line_status_register
-
- accept: event_info_struct
- perform: check for changes on the LSR
- return: 0 on success
- exceptions: none
- comments: not supported on all devices/drivers.
- ----------------------------------------------------------*/
- int check_line_status_register( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- #ifdef TIOCSERGETLSR
- struct stat fstatbuf;
-
- if( ! eis->eventflags[SPE_OUTPUT_BUFFER_EMPTY] )
- {
- report( "check_line_status_registe OUPUT_BUFFER_EMPTY not set\n" );
- return 0;
- }
- if ( fstat( eis->fd, &fstatbuf ) )
- {
- report( "check_line_status_register: fstat\n" );
- return( 1 );
- }
- if( ioctl( eis->fd, TIOCSERGETLSR, &eis->change ) )
- {
- report( "check_line_status_register: TIOCSERGETLSR\n is nonnull\n" );
- return( 1 );
- }
- else if( eis && eis->change )
- {
- report_verbose( "check_line_status_register: sending OUTPUT_BUFFER_EMPTY\n" );
- send_event( p, eis, SPE_OUTPUT_BUFFER_EMPTY, 1 );
- }
- #else
- /*
- printf("test %i\n", eis->output_buffer_empty_flag );
- */
- if( eis && eis->output_buffer_empty_flag == 1 &&
- eis->eventflags[SPE_OUTPUT_BUFFER_EMPTY] )
- {
- report_verbose("check_line_status_register: sending SPE_OUTPUT_BUFFER_EMPTY\n");
- send_event( p, eis, SPE_OUTPUT_BUFFER_EMPTY, 1 );
- /*
- send_event( this, eis, SPE_DATA_AVAILABLE, 1 );
- */
- eis->output_buffer_empty_flag = 0;
- }
- #endif /* TIOCSERGETLSR */
- return( 0 );
- }
-
- /*----------------------------------------------------------
- has_line_status_register_access
-
- accept: fd of interest
- perform: check for access to the LSR
- return: 0 if not available
- exceptions: none
- comments: not supported on all devices/drivers.
- JK00: work around for multiport cards without TIOCSERGETLSR
- Cyclades is one of those :-(
- ----------------------------------------------------------*/
- int has_line_status_register_access( int fd )
- {
- #if defined(TIOCSERGETLSR)
- int change;
-
- if( !ioctl( fd, TIOCSERGETLSR, &change ) ) {
- return(1);
- }
- #endif /* TIOCSERGETLSR */
- report( "has_line_status_register_acess: Port does not support TIOCSERGETLSR\n" );
- return( 0 );
- }
-
- /*----------------------------------------------------------
- check_cgi_count
-
- accept: fd of interest
- perform: check for access to TIOCGICOUNT
- return: 0 if not available
- exceptions: none
- comments: not supported on all devices/drivers.
- * 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);
- ----------------------------------------------------------*/
- void check_cgi_count( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- #if defined(TIOCGICOUNT)
-
- /* JK00: only use it if supported by this port */
-
- struct serial_icounter_struct sis;
- memcpy( &sis, &eis->osis, sizeof( struct serial_icounter_struct ) );
-
- if( ioctl( eis->fd, TIOCGICOUNT, &sis ) )
- {
- report( "check_cgi_count: TIOCGICOUNT\n is not 0\n" );
- return;
- }
- while( eis && sis.frame != eis->osis.frame ) {
- send_event( p, eis, SPE_FE, 1);
- eis->osis.frame++;
- }
- while( eis && sis.overrun != eis->osis.overrun ) {
- send_event( p, eis, SPE_OE, 1);
- eis->osis.overrun++;
- }
- while( eis && sis.parity != eis->osis.parity ) {
- send_event( p, eis, SPE_PE, 1);
- eis->osis.parity++;
- }
- while( eis && sis.brk != eis->osis.brk ) {
- send_event( p, eis, SPE_BI, 1);
- eis->osis.brk++;
- }
- if( eis )
- memcpy( &eis->osis, &sis, sizeof( struct serial_icounter_struct ) );
- #endif /* TIOCGICOUNT */
- }
-
- /*----------------------------------------------------------
- port_has_changed_fionread
-
- accept: fd of interest
- perform: check if FIONREAD has changed
- return: 0 if no data available
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- int port_has_changed_fionread( struct event_info_struct *eis )
- {
- int change, rc;
- char message[80];
-
- rc = ioctl( eis->fd, FIONREAD, &change );
- sprintf( message, "port_has_changed_fionread: change is %i ret is %i\n", change, eis->ret );
- #if defined(__unixware__) || defined(__sun__)
- /*
- On SCO OpenServer FIONREAD always fails for serial devices,
- so rely upon select() result to know whether data available.
-
- This is true for Solaris, also. taj.
- */
- if( (rc != -1 && change) || (rc == -1 && eis->ret > 0) )
- return( 1 );
- #else
- sprintf( message, "port_has_changed_fionread: change is %i\n", change );
- report_verbose( message );
- if( change )
- return( 1 );
- #endif /* __unixware__ || __sun__ */
- return( 0 );
- }
-
- /*----------------------------------------------------------
- check_tiocmget_changes
-
- accept: event_info_struct
- perform: use TIOCMGET to report events
- return: none
- exceptions: none
- comments: not supported on all devices/drivers.
- ----------------------------------------------------------*/
- void check_tiocmget_changes( gnu::io::RXTXPort *p, struct event_info_struct * eis )
- {
- unsigned int mflags = 0;
- int change;
-
- /* DORITO */
- if( !eis ) return;
- change = eis->change;
-
- report_verbose("entering check_tiocmget_changes\n");
- if( ioctl( eis->fd, TIOCMGET, &mflags ) )
- {
- report( "=======================================\n");
- report( "check_tiocmget_changes: ioctl(TIOCMGET)\n" );
- return;
- }
-
- change = (mflags&TIOCM_CTS) - (eis->omflags&TIOCM_CTS);
- if( eis && change ) send_event( p, eis, SPE_CTS, change );
-
- change = (mflags&TIOCM_DSR) - (eis->omflags&TIOCM_DSR);
- if( eis && change )
- {
- report( "sending DSR ===========================\n");
- send_event( p, eis, SPE_DSR, change );
- }
-
- change = (mflags&TIOCM_RNG) - (eis->omflags&TIOCM_RNG);
- if( eis && change ) send_event( p, eis, SPE_RI, change );
-
- change = (mflags&TIOCM_CD) - (eis->omflags&TIOCM_CD);
- if( eis && change ) send_event( p, eis, SPE_CD, change );
-
- if( eis )
- eis->omflags = mflags;
- report_verbose("leaving check_tiocmget_changes\n");
- }
-
- /*----------------------------------------------------------
- system_wait
-
- accept:
- perform:
- return:
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- void system_wait()
- {
- #if defined (__sun__ )
- struct timespec retspec, tspec;
- retspec.tv_sec = 0;
- retspec.tv_nsec = 100000000;
- do {
- tspec = retspec;
- nanosleep( &tspec, &retspec );
- } while( tspec.tv_nsec != 0 );
- /* Trent
- */
- #else
- #ifdef TRENT_IS_HERE_DEBUGGING_THREADS
- /* On NT4 The following was observed in a intense test:
- 50000 95% 179 sec
- 200000 95% 193 sec
- 1000000 95% 203 sec some callback failures sometimes.
- 2000000 0-95% callback failures.
- */
- #endif /* TRENT_IS_HERE_DEBUGGING_THREADS */
- #endif /* __sun__ */
- }
-
- /*----------------------------------------------------------
- driver_has_tiocgicount
-
- accept: fd of interest
- perform: check for access to TIOCGICOUNT
- return: 0 if not available
- exceptions: none
- comments: not supported on all devices/drivers.
- Some multiport serial cards do not implement TIOCGICOUNT ...
- So use the 'dumb' mode to enable using them after all! JK00
- ----------------------------------------------------------*/
- int driver_has_tiocgicount( struct event_info_struct * eis )
- {
- #if defined(TIOCGICOUNT)
-
- /* Some multiport serial cards do not implement TIOCGICOUNT ... */
- /* So use the 'dumb' mode to enable using them after all! JK00 */
-
- if( ioctl( eis->fd, TIOCGICOUNT, &eis->osis ) < 0 ) {
- report_verbose( " driver_has_tiocgicount: Port does not support TIOCGICOUNT events\n" );
- return(0);
- }
- else
- return(1);
- #endif /* TIOCGICOUNT */
- return(0);
-
- }
-
- /*----------------------------------------------------------
- report_serial_events
-
- accept: event_info_struct
- perform: send events if they occured
- return: 0 if not available
- exceptions: none
- comments: not supported on all devices/drivers.
- ----------------------------------------------------------*/
- void report_serial_events( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- /* JK00: work around for Multi IO cards without TIOCSERGETLSR */
- /* if( eis->has_tiocsergetlsr ) we have a fix for output empty */
- if( check_line_status_register( p, eis ) )
- return;
-
- #ifndef WIN32 /* something is wrong here */
- if ( eis && eis->has_tiocgicount )
- check_cgi_count( p, eis );
- #endif /* WIN32 */
-
- check_tiocmget_changes( p, eis );
-
- if( eis && port_has_changed_fionread( eis ) )
- {
- if(!eis->eventflags[SPE_DATA_AVAILABLE] )
- {
- report_verbose("report_serial_events: ignoring DATA_AVAILABLE\n");
- /*
- report(".");
- */
- #if !defined(__sun__)
- /* FIXME: No time to test on all OS's for production */
- usleep(20000);
- #endif /* !__sun__ */
- return;
- }
- report("report_serial_events: sending DATA_AVAILABLE\n");
- if(!send_event( p, eis, SPE_DATA_AVAILABLE, 1 ))
- {
- /* select wont block */
- #if !defined(__sun__)
- /* FIXME: No time to test on all OS's for production */
- usleep(20000);
- #endif /* !__sun__ */
- /*
- system_wait();
- */
- }
- }
- }
-
- /*----------------------------------------------------------
- initialise_event_info_struct
-
- accept: event_info_struct for this thread.
- perform: initialise or reset the event_info_struct
- return: 1 on success
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- int initialise_event_info_struct( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- int i;
- struct event_info_struct *index = master_index;
-
- if ( eis->initialised == 1 )
- goto end;
-
- #ifdef TIOCGICOUNT
- memset(&eis->osis,0,sizeof(eis->osis));
- #endif /* TIOCGICOUNT */
-
- if( index )
- {
- while( index->next )
- {
- index = index->next;
- }
- index->next = eis;
- eis->prev = index;
- eis->next = NULL;
- }
- else
- {
- master_index = eis;
- master_index->next = NULL;
- master_index->prev = NULL;
- }
-
- for( i = 0; i < 11; i++ ) eis->eventflags[i] = 0;
- #if !defined(TIOCSERGETLSR) && !defined(WIN32)
- eis->output_buffer_empty_flag = 0;
- eis->writing = 0;
- #endif /* TIOCSERGETLSR */
- eis->eventloop_interrupted = 0;
- eis->closing = 0;
-
- eis->fd = ( int ) p->fd;
- eis->has_tiocsergetlsr = has_line_status_register_access( eis->fd );
- eis->has_tiocgicount = driver_has_tiocgicount( eis );
-
- if( ioctl( eis->fd, TIOCMGET, &eis->omflags) < 0 ) {
- report( "initialise_event_info_struct: Port does not support events\n" );
- }
-
- end:
- FD_ZERO( &eis->rfds );
- FD_SET( eis->fd, &eis->rfds );
- eis->tv_sleep.tv_sec = 0;
- eis->tv_sleep.tv_usec = 1000;
- eis->initialised = 1;
- return( 1 );
- }
-
- /*----------------------------------------------------------
- finalize_event_info_struct
-
- accept: event_info_struct for this thread.
- perform: free resources
- return: none
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- void finalize_event_info_struct( struct event_info_struct *eis )
- {
- if( eis->next && eis->prev )
- {
- eis->prev->next = eis->next;
- eis->next->prev = eis->prev;
- }
- else if( eis->next )
- {
- eis->next->prev = NULL;
- master_index = eis->next;
- }
- else if( eis->prev )
- eis->prev->next = NULL;
- else master_index = NULL;
- }
-
- /*----------------------------------------------------------
- RXTXPort.eventLoop
-
- accept: none
- perform: periodically check for SerialPortEvents
- return: none
- exceptions: none
- comments: please keep this function clean.
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::eventLoop(
- )
- {
- struct event_info_struct eis;
- eis.initialised = 0;
-
- ENTER( "eventLoop\n" );
- if ( !initialise_event_info_struct( this, &eis ) ) goto end;
- if ( !init_threads( this, &eis ) ) goto end;
- unlock_monitor_thread( this, &eis );
- do{
- report_time_eventLoop( );
- do {
- /* report( "." ); */
- eis.ret = SELECT( eis.fd + 1, &eis.rfds, NULL, NULL,
- &eis.tv_sleep );
- /* nothing goes between this call and select */
- if( eis.closing )
- {
- report("eventLoop: got interrupt\n");
- finalize_threads( &eis );
- finalize_event_info_struct( &eis );
- this->MonitorThreadCloseLock = false;
- LEAVE("eventLoop");
- return;
- }
- usleep(20000);
- /*
- Trent system_wait();
- */
- } while ( eis.ret < 0 && errno == EINTR );
- if( eis.ret >= 0 )
- {
- report_serial_events( this, &eis );
- }
- initialise_event_info_struct( this, &eis );
- } while( 1 );
- end:
- LEAVE( "eventLoop: Bailing!\n" );
- }
-
- /*----------------------------------------------------------
- RXTXCommDriver.nativeGetVersion
-
- accept: none
- perform: return the current version
- return: version
- exceptions: none
- comments: This is used to avoid mixing versions of the .jar and
- native library.
- First introduced in rxtx-1.5-9
-
- ----------------------------------------------------------*/
- jstring gnu::io::RXTXCommDriver::nativeGetVersion (
- )
- {
- return JvNewStringUTF( "RXTX-2.1-7" );
- }
-
- /*----------------------------------------------------------
- RXTXCommDriver.testRead
-
- accept: jstr The device to be tested
- perform: test if the device can be read from
- return: true if the device can be read from
- exceptions: none
- comments: From Wayne Roberts wroberts1@home.com
- check tcget/setattr returns.
- support for non serial ports Trent
- ----------------------------------------------------------*/
-
- jboolean gnu::io::RXTXCommDriver::testRead(
- jstring jstr,
- jint port_type
- )
- {
- struct termios ttyset;
- char c;
- int i, fd, ret = true, pid = -1;
- //char filename[80];
- char filename[80];
- #ifdef TRENT_IS_HERE_DEBUGGING_ENUMERATION
- char message[80];
- #endif /* TRENT_IS_HERE_DEBUGGING_ENUMERATION */
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
- //java::lang::System::out->println( filename );
- //const char *filename = (const char *) jstr->toCharArray();
-
- /* We opened the file in this thread, use this pid to unlock */
- //java::lang::System::out->println( jstr );
- #ifndef WIN32
- pid = getpid();
- #else
- char full_windows_name[80];
- #endif /* WIN32 */
-
- ENTER( "RXTXPort:testRead" );
- //printf( "RXTXCommDriver::testRead( %s )\n", filename );
- #ifdef TRENT_IS_HERE_DEBUGGING_ENUMERATION
- /* vmware lies about which ports are there causing irq conflicts */
- /* this is for testing only */
- if( !strcmp( filename, "COM1" ) || !strcmp( filename, "COM2") )
- {
- printf("%s is good\n",filename);
- sprintf( message, "testRead: %s is good!\n", filename );
- report( message );
- return( true );
- }
- return( false );
- #endif /* TRENT_IS_HERE_DEBUGGING_ENUMERATION */
- #ifdef WIN32
- strcpy( full_windows_name, DEVICEDIR );
- strcat( full_windows_name, filename );
- ret = serial_test((char *) full_windows_name );
- return(ret);
- #endif /* WIN32 */
-
- /*
- LOCK is one of three functions defined in SerialImp.h
-
- uucp_lock Solaris
- fhs_lock Linux
- system_does_not_lock Win32
- */
- //printf( "RXTXCommDriver::testRead( %s )\n", filename );
-
- if ( LOCK( filename, pid ) )
- {
- LEAVE( "RXTXPort:testRead no lock" );
- return false;
- }
-
- /*
- CLOCAL eliminates open blocking on modem status lines
- -- changed to O_NONBLOCK
- */
- do {
- fd=::OPEN ( filename, O_RDWR | O_NOCTTY | O_NONBLOCK );
- } while ( fd < 0 && errno==EINTR );
-
- if( fd < 0 )
- {
- report_verbose( "testRead() open failed\n" );
- ret = false;
- goto END;
- }
-
- if ( port_type == PORT_SERIAL )
- {
- int saved_flags;
- struct termios saved_termios;
-
- if (tcgetattr(fd, &ttyset) < 0) {
- ret = false;
- goto END;
- }
-
- /* save, restore later */
- if ( ( saved_flags = fcntl(fd, F_GETFL ) ) < 0 )
- {
- report( "testRead() fcntl(F_GETFL) failed\n" );
- ret = false;
- goto END;
- }
-
- memcpy( &saved_termios, &ttyset, sizeof( struct termios ) );
-
- if ( fcntl( fd, F_SETFL, O_NONBLOCK ) < 0 )
- {
- report( "testRead() fcntl(F_SETFL) failed\n" );
- ret = false;
- goto END;
- }
-
- cfmakeraw(&ttyset);
- ttyset.c_cc[VMIN] = ttyset.c_cc[VTIME] = 0;
-
- if ( tcsetattr( fd, TCSANOW, &ttyset) < 0 )
- {
- report( "testRead() tcsetattr failed\n" );
- ret = false;
- tcsetattr( fd, TCSANOW, &saved_termios );
- goto END;
- }
-
- /*
-
- The following may mess up if both EAGAIN and EWOULDBLOCK
- are defined but only EWOULDBLOCK is used
-
- Linux:
-
- man 2 open
- O_NONBLOCK or O_NDELAY
- When possible, the file is opened in non-blocking
- mode. Neither the open nor any subsequent opera�
- tions on the file descriptor which is returned will
- cause the calling process to wait. For the han�
- dling of FIFOs (named pipes), see also fifo(4).
- This mode need not have any effect on files other
- than FIFOs.
-
- man 2 read
- EAGAIN
- Non-blocking I/O has been selected using O_NONBLOCK
- and no data was immediately available for reading.
-
-
- /usr/include/asm/error.h:
- #define EAGAIN 11 / Try again /
- #define EWOULDBLOCK EAGAIN / Operation would block /
-
- looks like the kernel is using EAGAIN
-
- -- should be OK
-
- Solaris:
-
- man 2 open
- EAGAIN The path argument names the slave side of a
- pseudo-terminal device that is locked.
-
- man 2 read
- If O_NONBLOCK is set, read() returns -1 and sets errno
- to EAGAIN.
-
- -- should be OK.
-
- HP-UX
-
- both are defined but EAGAIN is used.
-
- -- should be OK.
-
- Win32
-
- neither errno is currently set. Comment added to termios.c
- serial_open().
-
- -- should be OK
-
- Steven's book. Advanced programming in the Unix Environment pg 364
-
- "A common use for nonblocking I/O is for dealing with a terminal device
- for a network connection and these devices are normally used by one process
- at a time. This means that the change in the BSD semantics normally does 't
- effect us. The different error return, EWOULDBLOCK, instead of POSIX.1
- EAGAIN, continues to be a portability difference that we must deal with."
-
- */
-
- if ( READ( fd, &c, 1 ) < 0 )
- {
- #ifdef EAGAIN
- if ( errno != EAGAIN ) {
- report( "testRead() read failed\n" );
- ret = false;
- }
- #else
- #ifdef EWOULDBLOCK
- if ( errno != EWOULDBLOCK )
- {
- report( "testRead() read failed\n" );
- ret = false;
- }
- #else
- ret = false;
- #endif /* EWOULDBLOCK */
- #endif /* EAGAIN */
- }
-
- /* dont walk over unlocked open devices */
- tcsetattr( fd, TCSANOW, &saved_termios );
- fcntl( fd, F_SETFL, saved_flags );
- }
-
- /*
- UNLOCK is one of three functions defined in SerialImp.h
-
- uucp_unlock Solaris
- fhs_unlock Linux
- system_does_not_unlock Win32
- */
-
- END:
- UNLOCK(filename, pid );
- ::CLOSE( fd );
- LEAVE( "RXTXPort:testRead" );
- return ret;
- }
-
- #if defined(__APPLE__)
- /*----------------------------------------------------------
- createSerialIterator()
- accept:
- perform:
- return:
- exceptions:
- comments:
- Code courtesy of Eric Welch at Keyspan, except for the bugs
- which are courtesy of Joseph Goldstone (joseph@lp.com)
- ----------------------------------------------------------*/
-
- kern_return_t
- createSerialIterator(io_iterator_t *serialIterator)
- {
- kern_return_t kernResult;
- mach_port_t masterPort;
- CFMutableDictionaryRef classesToMatch;
- if ((kernResult=IOMasterPort(NULL, &masterPort)) != KERN_SUCCESS)
- {
- printf( "IOMasterPort returned %d\n", kernResult);
- return kernResult;
- }
- if ((classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue)) == NULL)
- {
- printf( "IOServiceMatching returned NULL\n" );
- return kernResult;
- }
- CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
- kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, serialIterator);
- if (kernResult != KERN_SUCCESS)
- {
- printf( "IOServiceGetMatchingServices returned %d\n", kernResult);
- }
- return kernResult;
- }
-
- /*----------------------------------------------------------
- getRegistryString()
-
- accept:
- perform:
- return:
- exceptions:
- comments:
- Code courtesy of Eric Welch at Keyspan, except for the bugs
- which are courtesy of Joseph Goldstone (joseph@lp.com)
- ----------------------------------------------------------*/
- char *
- getRegistryString(io_object_t sObj, char *propName)
- {
- static char resultStr[256];
- CFTypeRef nameCFstring;
- resultStr[0] = 0;
- nameCFstring = IORegistryEntryCreateCFProperty(sObj,
- CFStringCreateWithCString(kCFAllocatorDefault, propName, kCFStringEncodingASCII),
- kCFAllocatorDefault, 0);
- if (nameCFstring)
- {
- CFStringGetCString(nameCFstring, resultStr, sizeof(resultStr), kCFStringEncodingASCII);
- CFRelease(nameCFstring);
- }
- return resultStr;
- }
-
- /*----------------------------------------------------------
- registerKnownSerialPorts()
- accept:
- perform:
- return:
- exceptions:
- comments:
- ----------------------------------------------------------*/
- int
- registerKnownSerialPorts(
- jint portType
- ) /* dima */
- {
- io_iterator_t theSerialIterator;
- io_object_t theObject;
- int numPorts = 0;/* dima it should initiated */
- if (createSerialIterator(&theSerialIterator) != KERN_SUCCESS)
- {
- printf( "createSerialIterator failed\n" );
- } else {
- while (theObject = IOIteratorNext(theSerialIterator))
- {
- /* begin dima taj got this close for gcj */
- jstring tempJstring;
- tempJstring = JvNewStringUTF(getRegistryString(theObject, kIODialinDeviceKey));
- gnu::io::ComPortIdentifier->addPortName(tempJstring,portType,this);/* dima */
- numPorts++;
-
- tempJstring = JvNewStringUTF(getRegistryString(theObject, kIOCalloutDeviceKey));
- gnu::io::ComPortIdentifier->addPortName(tempJstring,portType,this);/* dima */
- numPorts++;
- /* end dima taj got this close for gcj */
- }
- }
- }
- return numPorts;
- }
- #endif /* __APPLE__ */
-
-
- /*----------------------------------------------------------
- registerKnownPorts
-
- accept: the type of port
- perform: register any ports of the desired type a priori known to this OS
- return: true if any such ports were registered otherwise false
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXCommDriver::registerKnownPorts(
- jint portType
- )
- {
- enum {PORT_TYPE_SERIAL = 1,
- PORT_TYPE_PARALLEL,
- PORT_TYPE_I2C,
- PORT_TYPE_RS485,
- PORT_TYPE_RAW};
- jboolean result = false;
- char message[80];
-
- switch(portType) {
- case PORT_TYPE_SERIAL:
- #if defined(__APPLE__)
- if (registerKnownSerialPorts( PORT_TYPE_SERIAL) > 0)
- {/* dima */
- result = true;
- }
- #endif
- break;
- case PORT_TYPE_PARALLEL: break;
- case PORT_TYPE_I2C: break;
- case PORT_TYPE_RS485: break;
- case PORT_TYPE_RAW: break;
- default:
- sprintf( message, "unknown portType %d handed to \
- native RXTXCommDriver.registerKnownPorts() \
- method.\n",
- (int) portType
- );
- report( message );
- }
- return result;
- }
-
- /*----------------------------------------------------------
- isPortPrefixValid
-
- accept: a port prefix
- perform: see if the port prefix matches a port that is valid on this OS.
- return: true if it exists otherwise false
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- jboolean gnu::io::RXTXCommDriver::isPortPrefixValid(
- jstring jstr
- )
- {
- jboolean result;
- static struct stat mystat;
- char teststring[256];
- int fd,i;
- char filename[80];
-
- for( i=0;i<jstr->length();i++)
- filename[i] = jstr->charAt(i);
- filename[i] = '\0';
-
- ENTER( "RXTXCommDriver:isPortPrefixValid" );
- for(i=0;i<64;i++){
- #if defined(__sun__)
- /* Solaris uses /dev/cua/a instead of /dev/cua0 */
- if( i > 25 ) break;
- sprintf(teststring,"%s%s%c",DEVICEDIR, name, i + 97 );
- fprintf(stderr, "testing: %s\n", teststring);
- #else
- #if defined(_GNU_SOURCE)
- snprintf(teststring, 256, "%s%s%i",DEVICEDIR,filename, i);
- #else
- sprintf(teststring,"%s%s%i",DEVICEDIR,filename, i);
- #endif /* _GNU_SOURCE */
- stat(teststring,&mystat);
- #endif /* __sun__ */
- /* XXX the following hoses freebsd when it tries to open the port later on */
- #ifndef __FreeBSD__
- if(S_ISCHR(mystat.st_mode)){
- fd=::OPEN(teststring,O_RDONLY|O_NONBLOCK);
- if (fd>0){
- ::CLOSE(fd);
- result=true;
- break;
- }
- else
- result=false;
- }
- else
- result=false;
- #else
- result=true;
- #endif /* __FreeBSD __ */
- }
- #if defined(_GNU_SOURCE)
- snprintf(teststring, 256, "%s%s",DEVICEDIR,filename);
- #else
- sprintf(teststring,"%s%s",DEVICEDIR,filename);
- #endif /* _GNU_SOURCE */
- stat(teststring,&mystat);
- if(S_ISCHR(mystat.st_mode)){
- fd=::OPEN(teststring,O_RDONLY|O_NONBLOCK);
- if (fd>0){
- ::CLOSE(fd);
- result=true;
- }
- }
- LEAVE( "RXTXCommDriver:isPortPrefixValid" );
- return(result);
- }
-
- /*----------------------------------------------------------
- getDeviceDirectory
-
- accept:
- perform:
- return: the directory containing the device files
- exceptions:
- comments: use this to avoid hard coded "/dev/"
- values are in SerialImp.h
- ----------------------------------------------------------*/
-
- jstring gnu::io::RXTXCommDriver::getDeviceDirectory(
- )
- {
- ENTER( "RXTXCommDriver:getDeviceDirectory" );
- return JvNewStringUTF(DEVICEDIR);
- LEAVE( "RXTXCommDriver:getDeviceDirectory" );
- }
-
- #ifdef GOING_TO_MESS_WITH_BUFFERS
- /*----------------------------------------------------------
- setInputBufferSize
-
- accept:
- perform:
- return: none
- exceptions: none
- comments: see fopen/fclose/fwrite/fread man pages.
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::setInputBufferSize(
- jint size
- )
- {
- report( "setInputBufferSize is not implemented\n" );
- }
-
- /*----------------------------------------------------------
- getIputBufferSize
-
- accept:
- perform:
- return: none
- exceptions: none
- comments: see fopen/fclose/fwrite/fread man pages.
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::getInputBufferSize(
- )
- {
- report( "getInputBufferSize is not implemented\n" );
- return(1);
- }
-
-
- /*----------------------------------------------------------
- setOutputBufferSize
-
- accept:
- perform:
- return: none
- exceptions: none
- comments: see fopen/fclose/fwrite/fread man pages.
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::setOutputBufferSize(
- jint size
- )
- {
- report( "setOutputBufferSize is not implemented\n" );
- }
-
- /*----------------------------------------------------------
- getOutputBufferSize
-
- accept:
- perform:
- return: none
- exceptions: none
- comments: see fopen/fclose/fwrite/fread man pages.
- ----------------------------------------------------------*/
- jint gnu::io::RXTXPort::getOutputBufferSize()
- {
- report( "getOutputBufferSize is not implemented\n" );
- return(1);
- }
-
- #endif /* GOING_TO_MESS_WITH_BUFFERS */
-
- /*----------------------------------------------------------
- interruptEventLoop
-
- accept: nothing
- perform: increment eventloop_interrupted
- return: nothing
- exceptions: none
- comments: all eventloops in this PID will check if their thread
- is interrupted. When all the interrupted threads exit
- they will decrement the var leaving it 0.
- the remaining threads will continue.
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::interruptEventLoop(
- )
- {
- struct event_info_struct *index = master_index;
- int fd = ( int ) this->fd;
- int searching = 1;
-
-
- while( searching )
- {
- index = master_index;
- if( index )
- {
- while( index->fd != fd &&
- index->next ) index = index->next;
- if ( index->fd == fd ) searching = 0;
- }
- else
- report("x");
- if( searching )
- {
- report("@");
- usleep(1000);
- }
- }
- index->eventloop_interrupted = 1;
- /*
- Many OS's need a thread running to determine if output buffer is
- empty. For Linux and Win32 it is not needed. So closing is used to
- shut down the thread in the write order on OS's that don't have
- kernel support for output buffer empty.
-
- In rxtx TIOCSERGETLSR is defined for win32 and Linux
- */
- #ifdef TIOCSERGETLSR
- index->closing=1;
- #endif /* TIOCSERGETLSR */
- #ifdef WIN32
- termios_interrupt_event_loop( index->fd, 1 );
- #endif /* WIN32 */
- report("interruptEventLoop: interrupted\n");
- }
-
- /*----------------------------------------------------------
- is_interrupted
-
- accept: event_info_struct
- perform: see if the port is being closed.
- return: a positive value if the port is being closed.
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- jboolean is_interrupted( gnu::io::RXTXPort *p, struct event_info_struct *eis )
- {
- int result;
-
- ENTER( "is_interrupted" );
- result = p->checkMonitorThread( );
- #ifdef DEBUG
- if((*env)->ExceptionOccurred(env)) {
- report ( "is_interrupted: an error occured calling sendEvent()\n" );
- (*env)->ExceptionDescribe(env);
- (*env)->ExceptionClear(env);
- }
- #endif /* DEBUG */
- LEAVE( "RXTXCommDriver:is_interrupted" );
- return(result);
- }
-
- /*----------------------------------------------------------
- nativeSetEventFlag
-
- accept: fd for finding the struct, event to flag, flag.
- perform: toggle the flag
- return: none
- exceptions: none
- comments: all the logic used to be done in Java but its too noisy
- ----------------------------------------------------------*/
- void gnu::io::RXTXPort::nativeSetEventFlag(
- jint fd,
- jint event,
- jboolean flag
- )
- {
- struct event_info_struct *index = master_index;
-
- if( !index )
- {
- report_error("nativeSetEventFlag !index\n");
- return;
- }
- while( index->fd != fd && index->next )
- {
- index = index->next;
- }
- if( index->fd != fd )
- {
- report_error("nativeSetEventFlag !fd\n");
- return;
- }
- index->eventflags[event] = (int) flag;
- #ifdef WIN32
- termios_setflags( fd, index->eventflags );
- #endif /* win32 */
-
- }
-
- /*----------------------------------------------------------
- send_event
-
- accept: event_info_structure, event type and true/false
- perform: if state is > 0 send a true event otherwise send false
- return: a positive value if the port is being closed.
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- int send_event( gnu::io::RXTXPort *p, struct event_info_struct *eis, jint type, int flag )
- {
- int result;
-
- ENTER( "send_event" );
- if( !eis || eis->eventloop_interrupted > 1 )
- {
- report("event loop interrupted\n");
- return true;
- }
- report_verbose("send_event: !eventloop_interupted\n");
-
- #ifdef TODO /* FIXME jcj hack */
- (*env)->ExceptionClear(env);
- #endif /* FIXME jcj hack */
-
- report_verbose("send_event: calling\n");
- result = p->sendEvent( type, flag > 0 ? true : false );
- report_verbose("send_event: called\n");
-
- #ifdef asdf
- if(!eis || (*eis->env)->ExceptionOccurred(eis->env)) {
- report ( "send_event: an error occured calling sendEvent()\n" );
- (*eis->env)->ExceptionDescribe(eis->env);
- (*eis->env)->ExceptionClear(eis->env);
- }
- #endif /* asdf */
- /* report("e"); */
- LEAVE( "send_event" );
- return(result);
- }
-
- /*----------------------------------------------------------
- report_warning
-
- accept: string to send to report as an message
- perform: send the string to stderr or however it needs to be reported.
- return: none
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- void report_warning(char *msg)
- {
- #ifndef DEBUG_MW
- fprintf(stderr, msg);
- #else
- mexWarnMsgTxt( (const char *) msg );
- #endif /* DEBUG_MW */
- }
-
- /*----------------------------------------------------------
- report_verbose
-
- accept: string to send to report as an verbose message
- perform: send the string to stderr or however it needs to be reported.
- return: none
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- void report_verbose(char *msg)
- {
- #ifdef DEBUG_VERBOSE
- #ifdef DEBUG_MW
- mexErrMsgTxt( msg );
- #else
- fprintf(stderr, msg);
- #endif /* DEBUG_MW */
- #endif /* DEBUG_VERBOSE */
- }
- /*----------------------------------------------------------
- report_error
-
- accept: string to send to report as an error
- perform: send the string to stderr or however it needs to be reported.
- return: none
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- void report_error(char *msg)
- {
- #ifndef DEBUG_MW
- fprintf(stderr, msg);
- #else
- mexWarnMsgTxt( msg );
- #endif /* DEBUG_MW */
- }
-
- /*----------------------------------------------------------
- report
-
- accept: string to send to stderr
- perform: if DEBUG is defined send the string to stderr.
- return: none
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- void report(char *msg)
- {
- #ifdef DEBUG
- # ifndef DEBUG_MW
- fprintf(stderr, msg);
- # else
- mexPrintf( msg );
- # endif /* DEBUG_MW */
- #endif /* DEBUG */
- }
-
- #ifndef WIN32
- #ifdef LFS
- /*----------------------------------------------------------
- lfs_lock
-
- accept: The name of the device to try to lock
- perform: Create a lock file if there is not one already using a
- lock file server.
- return: 1 on failure 0 on success
- exceptions: none
- comments:
-
- ----------------------------------------------------------*/
- int lfs_lock( const char *filename, int pid )
- {
- int s;
- int ret;
- int size = 1024;
- char *buffer = malloc(size);
- struct sockaddr_in addr;
-
- if ( !( s = socket( AF_INET, SOCK_STREAM, 0 ) ) > 0 )
- return 1;
- addr.sin_family = AF_INET;
- addr.sin_port = htons( 50001 );
- addr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
-
- if ( !connect( s, ( struct sockaddr * ) &addr, sizeof( addr ) ) == 0 )
- return 1;
- ret=recv( s, buffer, size, 0 );
- sprintf( buffer, "lock %s %i\n", filename, pid );
- /* printf( "%s", buffer ); */
- send( s, buffer, strlen(buffer), 0 );
- ret=recv( s, buffer, size, 0 );
- if ( ret > 0 )
- {
- buffer[ret] = '\0';
- /* printf( "Message recieved: %s", buffer ); */
- }
- send( s, "quit\n", strlen( "quit\n" ), 0 );
- close(s);
- /* printf("%s\n", buffer); */
- if( buffer[0] == '2' ) return 0;
- return 1;
- }
-
- /*----------------------------------------------------------
- lfs_unlock
-
- accept: The name of the device to try to unlock
- perform: Remove a lock file if there is one using a
- lock file server.
- return: 1 on failure 0 on success
- exceptions: none
- comments:
-
- ----------------------------------------------------------*/
- int lfs_unlock( const char *filename, int pid )
- {
- int s;
- int ret;
- int size = 1024;
- char *buffer = malloc(size);
- struct sockaddr_in addr;
-
- if ( !( s = socket( AF_INET, SOCK_STREAM, 0 ) ) > 0 )
- return 1;
- addr.sin_family = AF_INET;
- addr.sin_port = htons( 50001 );
- addr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
-
- if ( !connect( s, ( struct sockaddr * ) &addr, sizeof( addr ) ) == 0 )
- return 1;
- sprintf( buffer, "unlock %s %i\n", filename, pid );
- /* printf( "%s", buffer ); */
- send( s, buffer, strlen(buffer), 0 );
- ret = recv( s, buffer, size, 0 );
- if ( ret > 0 )
- {
- buffer[ret] = '\0';
- /* printf( "Message recieved: %s", buffer ); */
- }
- send( s, "quit\n", strlen( "quit\n" ), 0 );
- close(s);
- if( buffer[0] == '2' ) return 0;
- return 1;
- }
- #endif /* LFS */
-
- /*----------------------------------------------------------
- fhs_lock
-
- accept: The name of the device to try to lock
- termios struct
- perform: Create a lock file if there is not one already.
- return: 1 on failure 0 on success
- exceptions: none
- comments: This is for linux and freebsd only currently. I see SVR4 does
- this differently and there are other proposed changes to the
- Filesystem Hierachy Standard
-
- more reading:
-
- ----------------------------------------------------------*/
- int fhs_lock( const char *filename, int pid )
- {
- /*
- * There is a zoo of lockdir possibilities
- * Its possible to check for stale processes with most of them.
- * for now we will just check for the lockfile on most
- * Problem lockfiles will be dealt with. Some may not even be in use.
- *
- */
- int fd,j;
- char lockinfo[12], message[80];
- char file[80], *p;
-
- j = strlen( filename );
- p = ( char * ) filename + j;
- /* FIXME need to handle subdirectories /dev/cua/...
- SCO Unix use lowercase all the time
- taj
- */
- //printf("lock file is %s\n",filename);
- while( *( p - 1 ) != '/' && j-- != 1 )
- {
- #if defined ( __unixware__ )
- *p = tolower( *p );
- #endif /* __unixware__ */
- p--;
- }
- sprintf( file, "%s/LCK..%s", LOCKDIR, p );
- if ( check_lock_status( filename ) )
- {
- report( "fhs_lock() lockstatus fail\n" );
- return 1;
- }
- fd = open( file, O_CREAT | O_WRONLY | O_EXCL, 0444 );
- if( fd < 0 )
- {
- sprintf( message,
- "RXTX fhs_lock() Error: creating lock file: %s: %s\n",
- file, strerror(errno) );
- report_error( message );
- return 1;
- }
- sprintf( lockinfo, "%10d\n",(int) getpid() );
- sprintf( message, "fhs_lock: creating lockfile: %s\n", lockinfo );
- report( message );
- write( fd, lockinfo, 11 );
- close( fd );
- return 0;
- }
-
- /*----------------------------------------------------------
- uucp_lock
-
- accept: char * filename. Device to be locked
- perform: Try to get a uucp_lock
- return: int 0 on success
- exceptions: none
- comments:
- The File System Hierarchy Standard
- http://www.pathname.com/fhs/
-
- UUCP Lock Files
- http://docs.freebsd.org/info/uucp/uucp.info.UUCP_Lock_Files.html
-
- FSSTND
- ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/
-
- Proposed Changes to the File System Hierarchy Standard
- ftp://scicom.alphacdc.com/pub/linux/devlock-0.X.tgz
-
- "UNIX Network Programming", W. Richard Stevens,
- Prentice-Hall, 1990, pages 96-101.
-
- There is much to do here.
-
- 1) UUCP style locks (done)
- /var/spool/uucp
- 2) SVR4 locks
- /var/spool/locks
- 3) FSSTND locks (done)
- /var/lock
- 4) handle stale locks (done except kermit locks)
- 5) handle minicom lockfile contents (FSSTND?)
- " 16929 minicom root\n" (done)
- 6) there are other Lock conventions that use Major and Minor
- numbers...
- 7) Stevens recommends LCK..<pid>
-
- most are caught above. If they turn out to be problematic
- rather than an exercise, we will handle them.
-
- ----------------------------------------------------------*/
- int uucp_lock( const char *filename, int pid )
- {
- char lockfilename[80], lockinfo[12], message[80];
- char name[80];
- int fd;
- struct stat buf;
-
- sprintf( message, "uucp_lock( %s );\n", filename );
- report( message );
-
- if ( check_lock_status( filename ) )
- {
- report( "RXTX uucp check_lock_status true\n" );
- return 1;
- }
- if ( stat( LOCKDIR, &buf ) != 0 )
- {
- report( "RXTX uucp_lock() could not find lock directory.\n" );
- return 1;
- }
- if ( stat( filename, &buf ) != 0 )
- {
- report( "RXTX uucp_lock() could not find device.\n" );
- sprintf( message, "uucp_lock: device was %s\n", name );
- report( message );
- return 1;
- }
- sprintf( lockfilename, "%s/LK.%03d.%03d.%03d",
- LOCKDIR,
- (int) major( buf.st_dev ),
- (int) major( buf.st_rdev ),
- (int) minor( buf.st_rdev )
- );
- sprintf( lockinfo, "%10d\n", (int) getpid() );
- if ( stat( lockfilename, &buf ) == 0 )
- {
- sprintf( message, "RXTX uucp_lock() %s is there\n",
- lockfilename );
- report( message );
- report_error( message );
- return 1;
- }
- fd = open( lockfilename, O_CREAT | O_WRONLY | O_EXCL, 0444 );
- if( fd < 0 )
- {
- sprintf( message,
- "RXTX uucp_lock() Error: creating lock file: %s\n",
- lockfilename );
- report_error( message );
- return 1;
- }
- write( fd, lockinfo,11 );
- close( fd );
- return 0;
- }
-
- /*----------------------------------------------------------
- check_lock_status
-
- accept: the lock name in question
- perform: Make sure everything is sane
- return: 0 on success
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- int check_lock_status( const char *filename )
- {
- struct stat buf;
- /* First, can we find the directory? */
-
- if ( stat( LOCKDIR, &buf ) != 0 )
- {
- report( "check_lock_status: could not find lock directory.\n" );
- return 1;
- }
-
- /* OK. Are we able to write to it? If not lets bail */
-
- if ( check_group_uucp() )
- {
- report_error( "check_lock_status: No permission to create lock file.\nplease see: How can I use Lock Files with rxtx? in INSTALL\n" );
- return(1);
- }
-
- /* is the device alread locked */
-
- if ( is_device_locked( filename ) )
- {
- report( "check_lock_status: device is locked by another application\n" );
- return 1;
- }
- return 0;
-
- }
-
- /*----------------------------------------------------------
- fhs_unlock
-
- accept: The name of the device to unlock
- perform: delete the lock file
- return: none
- exceptions: none
- comments: This is for linux only currently. I see SVR4 does this
- differently and there are other proposed changes to the
- Filesystem Hierachy Standard
- ----------------------------------------------------------*/
- void fhs_unlock( const char *filename, int openpid )
- {
- char file[80],*p;
- int i;
-
- i = strlen( filename );
- p = ( char * ) filename + i;
- /* FIXME need to handle subdirectories /dev/cua/... */
- while( *( p - 1 ) != '/' && i-- != 1 ) p--;
- sprintf( file, "%s/LCK..%s", LOCKDIR, p );
-
- if( !check_lock_pid( file, openpid ) )
- {
- unlink(file);
- report("fhs_unlock: Removing LockFile\n");
- }
- else
- {
- report("fhs_unlock: Unable to remove LockFile\n");
- }
- }
-
- /*----------------------------------------------------------
- uucp_unlock
-
- accept: char *filename the device that is locked
- perform: remove the uucp lockfile if it exists
- return: none
- exceptions: none
- comments: http://docs.freebsd.org/info/uucp/uucp.info.UUCP_Lock_Files.html
- ----------------------------------------------------------*/
- void uucp_unlock( const char *filename, int openpid )
- {
- struct stat buf;
- char file[80], message[80];
- /* FIXME */
-
- sprintf( message, "uucp_unlock( %s );\n", filename );
- report( message );
-
- if ( stat( filename, &buf ) != 0 )
- {
- /* hmm the file is not there? */
- report( "uucp_unlock() no such device\n" );
- return;
- }
- sprintf( file, LOCKDIR"/LK.%03d.%03d.%03d",
- (int) major( buf.st_dev ),
- (int) major( buf.st_rdev ),
- (int) minor( buf.st_rdev )
- );
- if ( stat( file, &buf ) != 0 )
- {
- /* hmm the file is not there? */
- report( "uucp_unlock no such lockfile\n" );
- return;
- }
- if( !check_lock_pid( file, openpid ) )
- {
- sprintf( message, "uucp_unlock: unlinking %s\n", file );
- report( message );
- unlink(file);
- }
- else
- {
- sprintf( message, "uucp_unlock: unlinking failed %s\n", file );
- report( message );
- }
- }
-
- /*----------------------------------------------------------
- check_lock_pid
-
- accept: the name of the lockfile
- perform: make sure the lock file is ours.
- return: 0 on success
- exceptions: none
- comments:
- ----------------------------------------------------------*/
- int check_lock_pid( const char *file, int openpid )
- {
- int fd, lockpid;
- char pid_buffer[12];
- char message[80];
-
- fd=open( file, O_RDONLY );
- if ( fd < 0 )
- {
- return( 1 );
- }
- if ( read( fd, pid_buffer, 11 ) < 0 )
- {
- close( fd );
- return( 1 );
- }
- close( fd );
- pid_buffer[11] = '\0';
- lockpid = atol( pid_buffer );
- /* Native threads JVM's have multiple pids */
- if ( lockpid != getpid() && lockpid != getppid() && lockpid != openpid )
- {
- sprintf(message, "check_lock_pid: lock = %s pid = %i gpid=%i openpid=%i\n",
- pid_buffer, (int) getpid(), (int) getppid(), openpid );
- report( message );
- return( 1 );
- }
- return( 0 );
- }
-
- /*----------------------------------------------------------
- check_group_uucp
-
- accept: none
- perform: check if the user is root or in group uucp
- return: 0 on success
- exceptions: none
- comments:
- This checks if the effective user is in group uucp so we can
- create lock files. If not we give them a warning and bail.
- If its root we just skip the test.
-
- if someone really wants to override this they can use the USER_LOCK_DIRECTORY --not recommended.
-
- In a recent change RedHat 7.2 decided to use group lock.
- In order to get around this we just check the group id
- of the lock directory.
-
- * Modified to support Debian *
-
- The problem was that checking the ownership of the lock file
- dir is not enough, in the sense that even if the current user
- is not in the group of the lock directory if the lock
- directory has 777 permissions the lock file can be anyway
- created. My solution is simply to try to create a tmp file
- there and if it works then we can go on. Here is my code that
- I tried and seems to work.
-
- Villa Valerio <valerio.villa@siemens.com>
- ----------------------------------------------------------*/
- int check_group_uucp()
- {
- #ifndef USER_LOCK_DIRECTORY
- FILE *testLockFile ;
- char testLockFileDirName[] = LOCKDIR;
- char testLockFileName[] = "tmpXXXXXX";
- char *testLockAbsFileName;
-
- testLockAbsFileName = ( char * ) calloc(strlen(testLockFileDirName)
- + strlen(testLockFileName) + 2, sizeof(char));
- if ( NULL == testLockAbsFileName )
- {
- report_error("check_group_uucp(): Insufficient memory");
- return 1;
- }
- strcat(testLockAbsFileName, testLockFileDirName);
- strcat(testLockAbsFileName, "/");
- strcat(testLockAbsFileName, testLockFileName);
- if ( NULL == mkstemp(testLockAbsFileName) )
- {
- free(testLockAbsFileName);
- report_error("check_group_uucp(): mktemp malformed string - \
- should not happen");
-
- return 1;
- }
- testLockFile = fopen (testLockAbsFileName, "w+");
- if (NULL == testLockFile)
- {
- report_error("check_group_uucp(): error testing lock file \
- creation Error details: ");
- report_error(strerror(errno));
-
- free(testLockAbsFileName);
- return 1;
- }
-
- fclose (testLockFile);
- unlink (testLockAbsFileName);
- free(testLockAbsFileName);
-
- #endif /* USER_LOCK_DIRECTORY */
- return 0;
-
- #ifdef USE_OLD_CHECK_GROUP_UUCP
- int check_group_uucp()
- {
- #ifndef USER_LOCK_DIRECTORY
- int group_count;
- struct passwd *user = getpwuid( geteuid() );
- struct stat buf;
- char msg[80];
- gid_t list[ NGROUPS_MAX ];
-
- if( stat( LOCKDIR, &buf) )
- {
- sprintf( msg, "check_group_uucp: Can not find Lock Directory: %s\n", LOCKDIR );
- report_error( msg );
- return( 1 );
- }
- group_count = getgroups( NGROUPS_MAX, list );
- list[ group_count ] = geteuid();
-
- /* JJO changes start */
- if( user == NULL )
- {
- report_error( "Not able to get user groups.\n" );
- return 1;
- } else
- /* JJO changes stop */
-
-
- if( user->pw_gid )
- {
- while( group_count >= 0 && buf.st_gid != list[ group_count ] )
- {
- group_count--;
- }
- if( buf.st_gid == list[ group_count ] )
- return 0;
- sprintf( msg, "%i %i\n", buf.st_gid, list[ group_count ] );
- report_error( msg );
- report_error( UUCP_ERROR );
- return 1;
- }
- return 0;
- /*
- if( strcmp( user->pw_name, "root" ) )
- {
- while( *g->gr_mem )
- {
- if( !strcmp( *g->gr_mem, user->pw_name ) )
- {
- break;
- }
- (void) *g->gr_mem++;
- }
- if( !*g->gr_mem )
- {
- report( UUCP_ERROR );
- return 1;
- }
- }
- */
- #endif /* USER_LOCK_DIRECTORY */
- return 0;
- #endif /* USE_OLD_CHECK_GROUP_UUCP */
- }
-
- /*----------------------------------------------------------
- The following should be able to follow symbolic links. I think the stat
- method used below will work on more systems. This was found while looking
- for information.
-
- * realpath() doesn't exist on all of the systems my code has to run
- on (HP-UX 9.x, specifically)
- ----------------------------------------------------------
- int different_from_LOCKDIR(const char* ld)
- {
- char real_ld[MAXPATHLEN];
- char real_LOCKDIR[MAXPATHLEN];
- if (strncmp(ld, LOCKDIR, strlen(ld)) == 0)
- return 0;
- if (realpath(ld, real_ld) == NULL)
- return 1;
- if (realpath(LOCKDIR, real_LOCKDIR) == NULL)
- return 1;
- if (strncmp(real_ld, real_LOCKDIR, strlen(real_ld)) == 0)
- return 0;
- else
- return 1;
- }
- */
-
- /*----------------------------------------------------------
- is_device_locked
-
- accept: char * filename. The device in question including the path.
- perform: see if one of the many possible lock files is aready there
- if there is a stale lock, remove it.
- return: 1 if the device is locked or somethings wrong.
- 0 if its possible to create our own lock file.
- exceptions: none
- comments: check if the device is already locked
- ----------------------------------------------------------*/
- int is_device_locked( const char *port_filename )
- {
- const char *lockdirs[] = { "/etc/locks", "/usr/spool/kermit",
- "/usr/spool/locks", "/usr/spool/uucp", "/usr/spool/uucp/",
- "/usr/spool/uucp/LCK", "/var/lock", "/var/lock/modem",
- "/var/spool/lock", "/var/spool/locks", "/var/spool/uucp",
- LOCKDIR, NULL
- };
- const char *lockprefixes[] = { "LCK..", "lk..", "LK.", NULL };
- char *p, file[80], pid_buffer[20], message[80];
- int i = 0, j, k, fd , pid;
- struct stat buf;
- struct stat buf2;
-
- j = strlen( port_filename );
- p = ( char * ) port_filename+j;
- while( *( p-1 ) != '/' && j-- !=1 ) p--;
-
- while( lockdirs[i] )
- {
- /*
- Look for lockfiles in all known places other than the
- defined lock directory for this system
- report any unexpected lockfiles.
-
- Is the suspect lockdir there?
- if it is there is it not the expected lock dir?
- */
- if( !stat( lockdirs[i], &buf2 ) &&
- strncmp( lockdirs[i], LOCKDIR, strlen( lockdirs[i] ) ) )
- {
- j = strlen( port_filename );
- p = ( char * ) port_filename + j;
- /*
- SCO Unix use lowercase all the time
- taj
- */
- while( *( p - 1 ) != '/' && j-- != 1 )
- {
- #if defined ( __unixware__ )
- *p = tolower( *p );
- #endif /* __unixware__ */
- p--;
- }
- k=0;
- while ( lockprefixes[k] )
- {
- /* FHS style */
- sprintf( file, "%s/%s%s", lockdirs[i],
- lockprefixes[k], p );
- if( stat( file, &buf ) == 0 )
- {
- sprintf( message, UNEXPECTED_LOCK_FILE,
- file );
- report_warning( message );
- return 1;
- }
-
- /* UUCP style */
- stat(port_filename , &buf );
- sprintf( file, "%s/%s%03d.%03d.%03d",
- lockdirs[i],
- lockprefixes[k],
- (int) major( buf.st_dev ),
- (int) major( buf.st_rdev ),
- (int) minor( buf.st_rdev )
- );
- if( stat( file, &buf ) == 0 )
- {
- sprintf( message, UNEXPECTED_LOCK_FILE,
- file );
- report_warning( message );
- return 1;
- }
- k++;
- }
- }
- i++;
- }
-
- /*
- OK. We think there are no unexpect lock files for this device
- Lets see if there any stale lock files that need to be
- removed.
- */
-
- #ifdef FHS
- /* FHS standard locks */
- i = strlen( port_filename );
- p = ( char * ) port_filename + i;
- while( *(p-1) != '/' && i-- != 1)
- {
- #if defined ( __unixware__ )
- *p = tolower( *p );
- #endif /* __unixware__ */
- p--;
- }
- sprintf( file, "%s/%s%s", LOCKDIR, LOCKFILEPREFIX, p );
- #else
- /* UUCP standard locks */
- if ( stat( port_filename, &buf ) != 0 )
- {
- report( "RXTX is_device_locked() could not find device.\n" );
- return 1;
- }
- sprintf( file, "%s/LK.%03d.%03d.%03d",
- LOCKDIR,
- (int) major( buf.st_dev ),
- (int) major( buf.st_rdev ),
- (int) minor( buf.st_rdev )
- );
-
- #endif /* FHS */
-
- if( stat( file, &buf ) == 0 )
- {
-
- /* check if its a stale lock */
- fd=open( file, O_RDONLY );
- read( fd, pid_buffer, 11 );
- /* FIXME null terminiate pid_buffer? need to check in Solaris */
- close( fd );
- sscanf( pid_buffer, "%d", &pid );
-
- if( kill( (pid_t) pid, 0 ) && errno==ESRCH )
- {
- sprintf( message,
- "RXTX Warning: Removing stale lock file. %s\n",
- file );
- report_warning( message );
- if( unlink( file ) != 0 )
- {
- snprintf( message, 80, "RXTX Error: Unable to \
- remove stale lock file: %s\n",
- file
- );
- report_warning( message );
- return 1;
- }
- }
- }
- return 0;
- }
- #endif /* WIN32 */
-
- /*----------------------------------------------------------
- system_does_not_lock
-
- accept: the filename the system thinks should be locked.
- perform: avoid trying to create lock files on systems that dont use them
- return: 0 for success ;)
- exceptions: none
- comments: OS's like Win32 may not have lock files.
- ----------------------------------------------------------*/
- int system_does_not_lock( const char * filename, int pid )
- {
- return 0;
- }
-
- /*----------------------------------------------------------
- system_does_not_unlock
-
- accept: the filename the system thinks should be locked.
- perform: avoid trying to create lock files on systems that dont use them
- return: none
- exceptions: none
- comments: OS's like Win32 may not have lock files.
- ----------------------------------------------------------*/
- void system_does_not_unlock( const char * filename, int openpid )
- {
- return;
- }
-
- /*----------------------------------------------------------
- dump_termios
-
- accept: string to indicate where this was called.
- termios struct
- perform: print the termios struct to stderr.
- return: none
- exceptions: none
- comments: used to debug the termios struct.
- ----------------------------------------------------------*/
- void dump_termios(char *foo,struct termios *ttyset)
- {
- #ifdef DEBUG
- int i;
-
- fprintf(stderr, "%s c_iflag=%#x\n", foo, ttyset->c_iflag);
- fprintf(stderr, "%s c_lflag=%#x\n", foo, ttyset->c_lflag);
- fprintf(stderr, "%s c_oflag=%#x\n", foo, ttyset->c_oflag);
- fprintf(stderr, "%s c_cflag=%#x\n", foo, ttyset->c_cflag);
- fprintf(stderr, "%s c_cc[]: ", foo);
- for(i=0; i<NCCS; i++)
- {
- fprintf(stderr,"%d=%x ", i, ttyset->c_cc[i]);
- }
- fprintf(stderr,"\n" );
- #endif /* DEBUG */
- }
- /*----------------------------------------------------------
- printj
-
- accept: like vwprintf()
- return: number of jchars written or -1
- exceptions: none
- comments: prints data using System.out.print()
-
- for gcj + CNI
- Just use java::lang::System::out->println(s);
- ----------------------------------------------------------*/
- int printj(
- wchar_t *fmt,
- ...
- )
- {
- return(0);
- }
- /* for gcj compiles */
-
- jboolean gnu::io::RXTXPort::nativeSetCallOutHangup( jboolean NoHup )
- {
- return( true );
- }
- jboolean gnu::io::RXTXPort::nativeGetCallOutHangup( )
- {
- return( true );
- }
- jboolean gnu::io::RXTXPort::nativeSetLowLatency( )
- {
- return( true );
- }
- jboolean gnu::io::RXTXPort::nativeGetLowLatency( )
- {
- return( true );
- }
- jboolean gnu::io::RXTXPort::nativeSetUartType( jstring ty, jboolean te )
- {
- return( true );
- }
- jstring gnu::io::RXTXPort::nativeGetUartType( )
- {
- return JvNewStringUTF( "RXTX-2.1-7pre13 SAM I AM" );
- }
|