diff --git a/src/main/c/Makefile b/src/main/c/Makefile index d9569dd..68b3c90 100644 --- a/src/main/c/Makefile +++ b/src/main/c/Makefile @@ -164,8 +164,8 @@ arm32v7: # Requires gcc-arm-linux-gnueabihf. arm32v7HF: export CC := arm-linux-gnueabihf-gcc -arm32v7HF: export CFLAGS += $(LINUX_CFLAGS) -march=armv7-a -arm32v7HF: export LDFLAGS += -march=armv7-a +arm32v7HF: export CFLAGS += $(LINUX_CFLAGS) -march=armv7-a+fp +arm32v7HF: export LDFLAGS += -march=armv7-a+fp arm32v7HF: export platform := linux/ARM_32 arm32v7HF: export variant := v7_HF arm32v7HF: @@ -182,8 +182,8 @@ arm32v8: # Requires gcc-arm-linux-gnueabihf. arm32v8HF: export CC := arm-linux-gnueabihf-gcc -arm32v8HF: export CFLAGS += $(LINUX_CFLAGS) -march=armv8-a -arm32v8HF: export LDFLAGS += -march=armv8-a +arm32v8HF: export CFLAGS += $(LINUX_CFLAGS) -march=armv8-a+simd +arm32v8HF: export LDFLAGS += -march=armv8-a+simd arm32v8HF: export platform := linux/ARM_32 arm32v8HF: export variant := v8_HF arm32v8HF: diff --git a/src/main/c/include/termbits2.h b/src/main/c/include/termbits2.h new file mode 100644 index 0000000..55cc8f8 --- /dev/null +++ b/src/main/c/include/termbits2.h @@ -0,0 +1,166 @@ +/* + * termbits2.c + * + * Stuff that we should include from kernel sources, if we could; but + * we can't. Included from "termios2.h" + * + * by Nick Patavalis (npat@efault.net) + * + * ATTENTION: Linux-specific kludge! + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef TERMBITS2_H +#define TERMBITS2_H + +#ifndef __linux__ +#error "Linux specific code!" +#endif + +/* We need tcflag_t, cc_t, speed_t, CBAUDEX, etc */ +#include + +/* These definitions must correspond to the kernel structures as + defined in: + + /arch//include/uapi/asm/termbits.h + or /include/uapi/asm-generic/termbits.h + + which are the same as: + + /usr/include//asm/termbits.h + or /usr/include/asm-generic/termbits.h + + Unfortunatelly, we cannot just include or + or (all would do the trick) + because then "struct termios" would be re-defined to the kernel + version, which is not the same as the libc version. In effect, you + cannot both include and because both + define a "struct termios" which may or maynot be the same. We want + our "struct termios" here to be the libc version (as defined in + ), because that's what our callers use. As a result we + cannot get the definion of "struct termios2" from the above header + files, since this would also bring-in the clashing definition of the + kernel version of "struct termios". If you have an idea for a better + way out of this mess, I would REALLY like to hear it. + + I hope that soon GLIBC will pick-up termios2 and all these will be + useless. Until then ... + + ATTENTION: For most architectures "struct termios2" and the + associated constants we care about (NCCS, BOTHER, IBSHIFT) are the + same. For some there are small differences, and some architectures + do not support termios2 at all. I don't claim to have done a + thorough job figuring out the specifics for every architecture, so + your milleage may vary. In any case, if you want support for + something that's missing, just copy the relevant definitions from + the kernel header file in here, recompile, test, and send me a + patch. */ + +#if defined (__alpha__) + +#error "Architecure has no termios2 support" + + +#elif defined (__powerpc__) || defined (__powerpc64__) + +#define K_NCCS 19 +/* The "old" termios is the same with termios2 for powerpc's */ +struct termios2 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_cc[K_NCCS]; /* control characters */ + cc_t c_line; /* line discipline */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +#define BOTHER 00037 +#define IBSHIFT 16 + +/* powerpc ioctl numbers have the argument-size encoded. Make sure we + use the correct structure (i.e. kernel termios, not LIBC termios) + when calculating them. */ +#define IOCTL_SETS _IOW('t', 20, struct termios2) +#define IOCTL_SETSW _IOW('t', 21, struct termios2) +#define IOCTL_SETSF _IOW('t', 22, struct termios2) +#define IOCTL_GETS _IOR('t', 19, struct termios2) + + +#elif defined (__mips__) + +#define K_NCCS 23 +struct termios2 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[K_NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +#define BOTHER CBAUDEX +#define IBSHIFT 16 + +#define IOCTL_SETS TCSETS2 +#define IOCTL_SETSW TCSETSW2 +#define IOCTL_SETSF TCSETSF2 +#define IOCTL_GETS TCGETS2 + + +#else /* All others */ + +#define K_NCCS 19 +struct termios2 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[K_NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +#define BOTHER CBAUDEX +#define IBSHIFT 16 + +#define IOCTL_SETS TCSETS2 +#define IOCTL_SETSW TCSETSW2 +#define IOCTL_SETSF TCSETSF2 +#define IOCTL_GETS TCGETS2 + +#endif /* of architectures */ + +/***************************************************************************/ + +#endif /* of TERMBITS2_H */ + +/***************************************************************************/ + +/* + * Local Variables: + * mode:c + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/main/c/src/SerialImp.c b/src/main/c/src/SerialImp.c index 4fca01d..8efda68 100644 --- a/src/main/c/src/SerialImp.c +++ b/src/main/c/src/SerialImp.c @@ -121,6 +121,7 @@ #include # include # include +#include "termbits2.h" #endif /* __linux__ */ #if defined(__sun__) # include @@ -506,6 +507,9 @@ set_java_vars void set_java_vars( JNIEnv *env, jobject jobj, int fd ) { struct termios ttyset; +#if defined(IOCTL_GETS) /* termios2 access */ + struct termios2 ttyset2; +#endif int databits = -1; int jparity = -1; int stop_bits = STOPBITS_1_5; @@ -574,12 +578,21 @@ cf{get,set}{i,o}speed and shouldn't be provided or used. */ #if defined(CBAUD)/* dima */ - baudrate = ttyset.c_cflag&CBAUD; + baudrate = ttyset.c_cflag&CBAUD; #else - baudrate = cfgetispeed(&ttyset); -#endif - (*env)->SetIntField(env, jobj, jfspeed, - ( jint ) get_java_baudrate(baudrate) ); + baudrate = cfgetispeed(&ttyset); +#endif /* CBAUD */ +#if defined(IOCTL_GETS) /* termios2 access */ + if (baudrate == BOTHER && ioctl(fd, IOCTL_GETS, &ttyset2) >= 0){ + baudrate = ttyset2.c_ospeed; + } else { + baudrate = get_java_baudrate(baudrate); + } +#else + baudrate = get_java_baudrate(baudrate); +#endif /* IOCTL_GETS */ + + (*env)->SetIntField(env, jobj, jfspeed, ( jint ) baudrate ); (*env)->SetIntField(env, jobj, jfdataBits, ( jint ) databits ); (*env)->SetIntField(env, jobj, jfstopBits, ( jint ) stop_bits ); (*env)->SetIntField(env, jobj, jfparity, ( jint ) jparity ); @@ -832,6 +845,37 @@ JNIEXPORT void JNICALL RXTXPort(nativeClose)( JNIEnv *env, return; } +/*---------------------------------------------------------- + translate_port_params + + accept: gnu.io.SerialPort.* constants + perform: set proper termios c_cflag bits + return: 1 on error + exceptions: UnsupportedCommOperationException +----------------------------------------------------------*/ +int translate_port_params( JNIEnv *env, tcflag_t *cflag, int dataBits, + int stopBits, int parity ) +{ + if( translate_data_bits( env, cflag, dataBits ) ) + { + report( "set_port_params: Invalid Data Bits Selected\n" ); + return(1); + } + + if( translate_stop_bits( env, cflag, stopBits ) ) + { + report( "set_port_params: Invalid Stop Bits Selected\n" ); + return(1); + } + + if( translate_parity( env, cflag, parity ) ) + { + report( "set_port_params: Invalid Parity Selected\n" ); + return(1); + } + return (0); +} + /*---------------------------------------------------------- RXTXPort.set_port_params @@ -845,14 +889,18 @@ JNIEXPORT void JNICALL RXTXPort(nativeClose)( JNIEnv *env, see: nativeSetSerialPortParams & nativeStaticSerialPortParams ----------------------------------------------------------*/ -int set_port_params( JNIEnv *env, int fd, int cspeed, int dataBits, +int set_port_params( JNIEnv *env, int fd, int speed, int dataBits, int stopBits, int parity ) { struct termios ttyset; +#if defined(IOCTL_SETS) /* termios2 access */ + struct termios2 ttyset2; +#endif int result = 0; #if defined(TIOCGSERIAL) struct serial_struct sstruct; #endif /* TIOCGSERIAL */ + int cspeed = translate_speed( env, speed ); if( tcgetattr( fd, &ttyset ) < 0 ) { @@ -860,24 +908,6 @@ int set_port_params( JNIEnv *env, int fd, int cspeed, int dataBits, return(1); } - if( translate_data_bits( env, &(ttyset.c_cflag), dataBits ) ) - { - report( "set_port_params: Invalid Data Bits Selected\n" ); - return(1); - } - - if( translate_stop_bits( env, &(ttyset.c_cflag), stopBits ) ) - { - report( "set_port_params: Invalid Stop Bits Selected\n" ); - return(1); - } - - if( translate_parity( env, &(ttyset.c_cflag), parity ) ) - { - report( "set_port_params: Invalid Parity Selected\n" ); - return(1); - } - #ifdef __FreeBSD__ if( cfsetspeed( &ttyset, cspeed ) < 0 ) { @@ -885,7 +915,7 @@ int set_port_params( JNIEnv *env, int fd, int cspeed, int dataBits, return( 1 ); } #endif /* __FreeBSD__ */ - if( !cspeed ) + if( !speed ) { /* hang up the modem aka drop DTR */ /* Unix should handle this */ @@ -896,9 +926,24 @@ int set_port_params( JNIEnv *env, int fd, int cspeed, int dataBits, result &= ~TIOCM_DTR; ioctl( fd, TIOCMSET, &result ); } - if( cfsetispeed( &ttyset, cspeed ) < 0 || +#if defined(IOCTL_SETS) /* termios2 access */ + if( (speed != 0 && speed == cspeed) || //custom baudrate + cfsetispeed( &ttyset, cspeed ) < 0 || + cfsetospeed( &ttyset, cspeed ) < 0 ) + { + if (speed > 0 && ioctl(fd, IOCTL_GETS, &ttyset2) >= 0){ + ttyset2.c_cflag &= ~(((CBAUD | CBAUDEX) << IBSHIFT) | CBAUD); + ttyset2.c_cflag |= BOTHER; + ttyset2.c_ospeed = speed; + if (translate_port_params(env, &(ttyset2.c_cflag), dataBits, stopBits, parity)) + return (1); + if (ioctl(fd, IOCTL_SETS, &ttyset2) >= 0) return (0); + } +#else /* IOCTL_SETS */ + if( cfsetispeed( &ttyset, cspeed ) < 0 || cfsetospeed( &ttyset, cspeed ) < 0 ) { +#endif /* IOCTL_SETS */ /* Some people need to set the baud rate to ones not defined in termios.h @@ -915,11 +960,16 @@ int set_port_params( JNIEnv *env, int fd, int cspeed, int dataBits, On linux the setserial man page covers this. */ + #if defined(TIOCGSERIAL) - sstruct.custom_divisor = ( sstruct.baud_base/cspeed ); + if ( ioctl( fd, TIOCGSERIAL, &sstruct ) < 0 ) //sstruct is initialised here! + { + report( "set_port_params: Cannot Get Serial Port Settings\n" ); + return(1); + } + sstruct.custom_divisor = ( sstruct.baud_base/speed ); cspeed = B38400; -#endif /* TIOCGSERIAL */ if( cfsetispeed( &ttyset, cspeed ) < 0 || cfsetospeed( &ttyset, cspeed ) < 0 ) { @@ -927,16 +977,21 @@ int set_port_params( JNIEnv *env, int fd, int cspeed, int dataBits, 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 */ +#else /* TIOCSSERIAL */ + /* OK, we tried everything */ + report( "nativeSetSerialPortParams: Cannot Set Speed\n" ); + return( 1 ); +#endif /* TIOCSSERIAL */ } + if (translate_port_params(env, &(ttyset.c_cflag), dataBits, stopBits, parity)) + return (1); if( tcsetattr( fd, TCSANOW, &ttyset ) < 0 ) { report("tcsetattr returns nonzero value!\n"); @@ -958,14 +1013,13 @@ JNIEXPORT jboolean JNICALL RXTXPort(nativeSetSerialPortParams)( jint parity ) { int fd = get_java_var( env, jobj,"fd","I" ); - int cspeed = translate_speed( env, speed ); ENTER( "RXTXPort:nativeSetSerialPortParams" ); report_time_start( ); - if (cspeed < 0 ) + if (speed < 0 ) { - report(" invalid cspeed\n"); + report(" invalid speed\n"); /* For some reason the native exceptions are not being caught. Moving this to the Java side fixed the issue. taj. @@ -976,7 +1030,7 @@ JNIEXPORT jboolean JNICALL RXTXPort(nativeSetSerialPortParams)( } - if( set_port_params( env, fd, cspeed, dataBits, stopBits, parity ) ) + if( set_port_params( env, fd, speed, dataBits, stopBits, parity ) ) { report("set_port_params failed\n"); LEAVE( "RXTXPort:nativeSetSerialPortParams" ); @@ -989,6 +1043,7 @@ JNIEXPORT jboolean JNICALL RXTXPort(nativeSetSerialPortParams)( return(1); } + set_java_vars( env, jobj, fd ); LEAVE( "RXTXPort:nativeSetSerialPortParams" ); report_time_end( ); return(0); @@ -2400,7 +2455,6 @@ JNIEXPORT void JNICALL RXTXPort(nativeStaticSetSerialPortParams) (JNIEnv *env, int fd; int pid = -1; const char *filename = (*env)->GetStringUTFChars( env, jstr, 0 ); - int cspeed = translate_speed( env, baudrate ); ENTER( "RXTXPort:nativeStaticSetSerialPortParams" ); @@ -2429,7 +2483,7 @@ JNIEXPORT void JNICALL RXTXPort(nativeStaticSetSerialPortParams) (JNIEnv *env, return; } - if (cspeed == -1) + if (baudrate < 0) { (*env)->ReleaseStringUTFChars( env, jstr, filename ); throw_java_exception( env, UNSUPPORTED_COMM_OPERATION, @@ -2437,7 +2491,7 @@ JNIEXPORT void JNICALL RXTXPort(nativeStaticSetSerialPortParams) (JNIEnv *env, return; } - if( set_port_params( env, fd, cspeed, dataBits, stopBits, parity ) ) + if( set_port_params( env, fd, baudrate, dataBits, stopBits, parity ) ) { (*env)->ReleaseStringUTFChars( env, jstr, filename ); LEAVE( "RXTXPort:nativeStatic SetSerialPortParams" ); @@ -3864,8 +3918,10 @@ int has_line_status_register_access( int fd ) if( !ioctl( fd, TIOCSERGETLSR, &change ) ) { return(1); } + report( "has_line_status_register_access: Port does not support TIOCSERGETLSR\n" ); +#else /* TIOCSERGETLSR */ + report( "has_line_status_register_access: System does not support TIOCSERGETLSR\n" ); #endif /* TIOCSERGETLSR */ - report( "has_line_status_register_acess: Port does not support TIOCSERGETLSR\n" ); return( 0 ); } diff --git a/src/main/java/gnu/io/RXTXPort.java b/src/main/java/gnu/io/RXTXPort.java index c9604e8..f6933ab 100644 --- a/src/main/java/gnu/io/RXTXPort.java +++ b/src/main/java/gnu/io/RXTXPort.java @@ -256,14 +256,13 @@ public synchronized void setSerialPortParams( int b, int d, int s, if (debug) z.reportln( "RXTXPort:setSerialPortParams(" + b + " " + d + " " + s + " " + p + ") called"); - if ( nativeSetSerialPortParams( b, d, s, p ) ) - throw new UnsupportedCommOperationException( - "Invalid Parameter" ); speed = b; - if( s== STOPBITS_1_5 ) dataBits = DATABITS_5; - else dataBits = d; + dataBits = ( s == STOPBITS_1_5 ) ? DATABITS_5 : d; stopBits = s; parity = p; + if ( nativeSetSerialPortParams( b, d, s, p ) ) + throw new UnsupportedCommOperationException( + "Invalid Parameter" ); z.reportln( "RXTXPort:setSerialPortParams(" + b + " " + d + " " + s + " " + p + ") returning");