From a7ec5da1d1ba05291d03858d4aad3b75f57e6df1 Mon Sep 17 00:00:00 2001 From: "Andreas Fankhauser hiddenalpha.ch" <23085769+hiddenalpha@users.noreply.github.com> Date: Sun, 27 Jul 2025 19:03:57 +0200 Subject: [PATCH 1/2] Make writeBytes() return how many bytes actually got written The core change is this one: --- src/main/java/jssc/SerialNativeInterface.java +++ src/main/java/jssc/SerialNativeInterface.java @@ -278,5 +278,5 @@ public class SerialNativeInterface { * @return If the operation is successfully completed, the method returns true, otherwise false */ - public native boolean writeBytes(long handle, byte[] buffer) throws IOException; + public native int writeBytes(long handle, byte[] buffer) throws IOException; /** Essentially changing the return type of `writeBytes()` from `boolean` to `int`. The reason behind this is that we can return how many bytes actually got written, in place of just true/false. Basically, this is a very small change. Nevertheless, there are some consequences. This is (kind of) a breaking change for the java API. But still not really an issue, as it is a very easy migration. About how to migrate, one can just do the same as done in `SerialPort.writeBytes1()` (notice the '1' in the name). Just check if returned value matches the length of the passed-in array. There is also a YAGNI approach (NOT RECOMMENDED!): One could just use `writeBytes1()` instead. Which provides the old behavior. A more severe issue can arise because it potentially also breaks the ABI. make sure to NOT mix usage of parts of jssc built before or after this change! in most cases this shouldn't be an issue, as jssc unpacks the correct version from its JAR anyway. BUT FOR THOSE WHO DID SEPARATE THE JAVA CODE FROM THE NATIVE CODE AND INSTALL IT SEPARATELY, THEY POTENTIALLY CAN END UP IN TROUBLE WHEN NOT TAKING CARE HERE. In addition, this commit also contains some minor cleanups and fixes some compiler warnings. Related: - https://github.com/java-native/jssc/issues/129 (wip @ 17cc247b69cdae978ad7192a21548162fe118f2a) --- src/main/cpp/_nix_based/jssc.cpp | 51 +++--- src/main/cpp/jssc_SerialNativeInterface.h | 173 ------------------ src/main/cpp/windows/jssc.cpp | 70 +++++-- src/main/java/jssc/SerialNativeInterface.java | 2 +- src/main/java/jssc/SerialPort.java | 36 +++- 5 files changed, 110 insertions(+), 222 deletions(-) delete mode 100644 src/main/cpp/jssc_SerialNativeInterface.h diff --git a/src/main/cpp/_nix_based/jssc.cpp b/src/main/cpp/_nix_based/jssc.cpp index cab25db09..db70486f7 100644 --- a/src/main/cpp/_nix_based/jssc.cpp +++ b/src/main/cpp/_nix_based/jssc.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,6 @@ #endif #ifdef __sun #include //Needed for FIONREAD in Solaris - #include //Needed for select() function #endif #ifdef __APPLE__ #include //Needed for IOSSIOSPEED in Mac OS X (Non standard baudrate) @@ -62,7 +60,16 @@ #include #include "version.h" -//#include //-lCstd use for Solaris linker +#if defined(_MSC_VER) && _MSC_VER < 1800 +# define PRIsz "Iu" +# define PRIssz "Id" +#elif defined(__MINGW32__) && !defined(__MINGW64__) +# define PRIsz "u" +# define PRIssz "d" +#else +# define PRIsz "zu" +# define PRIssz "zd" +#endif /* * Get native library version @@ -529,33 +536,31 @@ JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR /* * Writing data to the port */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes +JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_writeBytes (JNIEnv *env, jobject, jlong portHandle, jbyteArray buffer){ - if( buffer == NULL ){ + ssize_t ret = 0; + jbyte *jBuffer = NULL; + if( !buffer ){ jclass exClz = env->FindClass("java/lang/NullPointerException"); - if( exClz != NULL ) env->ThrowNew(exClz, "buffer"); - return 0; + if( exClz ) env->ThrowNew(exClz, "buffer"); + goto Finally; } - jboolean ret = JNI_FALSE; - jbyte* jBuffer = env->GetByteArrayElements(buffer, JNI_FALSE); - if( jBuffer == NULL ){ - jclass exClz = env->FindClass("java/lang/RuntimeException"); - if( exClz != NULL ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed"); - return 0; + jBuffer = env->GetByteArrayElements(buffer, NULL); + if( !jBuffer ){ + jclass exClz = env->ExceptionCheck() ? NULL : env->FindClass("java/lang/RuntimeException"); + if( exClz ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed"); + goto Finally; } - jint bufferSize = env->GetArrayLength(buffer); - jint result = write(portHandle, jBuffer, (size_t)bufferSize); - if( result == -1 ){ - int err = errno; /*bakup errno*/ + ret = write(portHandle, jBuffer, env->GetArrayLength(buffer)); + if( ret == -1 ){ + int err = errno; jclass exClz = env->FindClass("java/io/IOException"); - assert(exClz != NULL); - env->ThrowNew(exClz, strerror(err)); + if( exClz ) env->ThrowNew(exClz, strerror(err)); goto Finally; } - ret = (result == bufferSize) ? JNI_TRUE : JNI_FALSE; Finally: - env->ReleaseByteArrayElements(buffer, jBuffer, 0); - return ret; + if( jBuffer ) env->ReleaseByteArrayElements(buffer, jBuffer, 0); + return (jint)ret; } /** @@ -676,7 +681,7 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer); if( !lpBuffer ){ char emsg[32]; emsg[0] = '\0'; - snprintf(emsg, sizeof emsg, "malloc(%d) failed", byteCount*sizeof*lpBuffer); + snprintf(emsg, sizeof emsg, "malloc(%" PRIsz ") failed", byteCount*sizeof*lpBuffer); jclass exClz = env->FindClass("java/lang/RuntimeException"); if( exClz ) env->ThrowNew(exClz, emsg); returnArray = NULL; goto Finally; diff --git a/src/main/cpp/jssc_SerialNativeInterface.h b/src/main/cpp/jssc_SerialNativeInterface.h deleted file mode 100644 index afde9b032..000000000 --- a/src/main/cpp/jssc_SerialNativeInterface.h +++ /dev/null @@ -1,173 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class jssc_SerialNativeInterface */ - -#ifndef _Included_jssc_SerialNativeInterface -#define _Included_jssc_SerialNativeInterface -#ifdef __cplusplus -extern "C" { -#endif -#undef jssc_SerialNativeInterface_OS_LINUX -#define jssc_SerialNativeInterface_OS_LINUX 0L -#undef jssc_SerialNativeInterface_OS_WINDOWS -#define jssc_SerialNativeInterface_OS_WINDOWS 1L -#undef jssc_SerialNativeInterface_OS_SOLARIS -#define jssc_SerialNativeInterface_OS_SOLARIS 2L -#undef jssc_SerialNativeInterface_OS_MAC_OS_X -#define jssc_SerialNativeInterface_OS_MAC_OS_X 3L -#undef jssc_SerialNativeInterface_ERR_PORT_BUSY -#define jssc_SerialNativeInterface_ERR_PORT_BUSY -1LL -#undef jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND -#define jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND -2LL -#undef jssc_SerialNativeInterface_ERR_PERMISSION_DENIED -#define jssc_SerialNativeInterface_ERR_PERMISSION_DENIED -3LL -#undef jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT -#define jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT -4LL -/* - * Class: jssc_SerialNativeInterface - * Method: getNativeLibraryVersion - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_jssc_SerialNativeInterface_getNativeLibraryVersion - (JNIEnv *, jclass); - -/* - * Class: jssc_SerialNativeInterface - * Method: openPort - * Signature: (Ljava/lang/String;Z)J - */ -JNIEXPORT jlong JNICALL Java_jssc_SerialNativeInterface_openPort - (JNIEnv *, jobject, jstring, jboolean); - -/* - * Class: jssc_SerialNativeInterface - * Method: setParams - * Signature: (JIIIIZZI)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setParams - (JNIEnv *, jobject, jlong, jint, jint, jint, jint, jboolean, jboolean, jint); - -/* - * Class: jssc_SerialNativeInterface - * Method: purgePort - * Signature: (JI)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_purgePort - (JNIEnv *, jobject, jlong, jint); - -/* - * Class: jssc_SerialNativeInterface - * Method: closePort - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_closePort - (JNIEnv *, jobject, jlong); - -/* - * Class: jssc_SerialNativeInterface - * Method: setEventsMask - * Signature: (JI)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setEventsMask - (JNIEnv *, jobject, jlong, jint); - -/* - * Class: jssc_SerialNativeInterface - * Method: getEventsMask - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getEventsMask - (JNIEnv *, jobject, jlong); - -/* - * Class: jssc_SerialNativeInterface - * Method: waitEvents - * Signature: (J)[[I - */ -JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_waitEvents - (JNIEnv *, jobject, jlong); - -/* - * Class: jssc_SerialNativeInterface - * Method: setRTS - * Signature: (JZ)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setRTS - (JNIEnv *, jobject, jlong, jboolean); - -/* - * Class: jssc_SerialNativeInterface - * Method: setDTR - * Signature: (JZ)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR - (JNIEnv *, jobject, jlong, jboolean); - -/* - * Class: jssc_SerialNativeInterface - * Method: readBytes - * Signature: (JI)[B - */ -JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes - (JNIEnv *, jobject, jlong, jint); - -/* - * Class: jssc_SerialNativeInterface - * Method: writeBytes - * Signature: (J[B)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes - (JNIEnv *, jobject, jlong, jbyteArray); - -/* - * Class: jssc_SerialNativeInterface - * Method: getBuffersBytesCount - * Signature: (J)[I - */ -JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getBuffersBytesCount - (JNIEnv *, jobject, jlong); - -/* - * Class: jssc_SerialNativeInterface - * Method: setFlowControlMode - * Signature: (JI)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setFlowControlMode - (JNIEnv *, jobject, jlong, jint); - -/* - * Class: jssc_SerialNativeInterface - * Method: getFlowControlMode - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getFlowControlMode - (JNIEnv *, jobject, jlong); - -/* - * Class: jssc_SerialNativeInterface - * Method: getSerialPortNames - * Signature: ()[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_getSerialPortNames - (JNIEnv *, jobject); - -/* - * Class: jssc_SerialNativeInterface - * Method: getLinesStatus - * Signature: (J)[I - */ -JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getLinesStatus - (JNIEnv *, jobject, jlong); - -/* - * Class: jssc_SerialNativeInterface - * Method: sendBreak - * Signature: (JI)Z - */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_sendBreak - (JNIEnv *, jobject, jlong, jint); - -#ifdef __cplusplus -} -#endif -#endif \ No newline at end of file diff --git a/src/main/cpp/windows/jssc.cpp b/src/main/cpp/windows/jssc.cpp index 0f08718f0..45c163d99 100644 --- a/src/main/cpp/windows/jssc.cpp +++ b/src/main/cpp/windows/jssc.cpp @@ -29,7 +29,16 @@ #include #include "version.h" -//#include +#if defined(_MSC_VER) && _MSC_VER < 1800 +# define PRIsz "Iu" +# define PRIssz "Id" +#elif defined(__MINGW32__) && !defined(__MINGW64__) +# define PRIsz "u" +# define PRIssz "d" +#else +# define PRIsz "zu" +# define PRIssz "zd" +#endif #define MAX_PORT_NAME_STR_LEN 32 @@ -232,38 +241,61 @@ JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR * portHandle - port handle * buffer - byte array for sending */ -JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes +JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_writeBytes (JNIEnv *env, jobject, jlong portHandle, jbyteArray buffer){ HANDLE hComm = (HANDLE)portHandle; DWORD lpNumberOfBytesTransferred; DWORD lpNumberOfBytesWritten; - jboolean returnValue = JNI_FALSE; - if( buffer == NULL ){ + jint returnValue = -1; + if( !buffer ){ jclass exClz = env->FindClass("java/lang/NullPointerException"); - if( exClz != NULL ) env->ThrowNew(exClz, "buffer"); + if( exClz ) env->ThrowNew(exClz, "buffer"); return 0; } - jbyte* jBuffer = env->GetByteArrayElements(buffer, JNI_FALSE); - if( jBuffer == NULL ){ - jclass exClz = env->FindClass("java/lang/RuntimeException"); - if( exClz != NULL ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed"); + jbyte *jBuffer = env->GetByteArrayElements(buffer, NULL); + if( !jBuffer ){ + jclass exClz = env->ExceptionCheck() ? NULL : env->FindClass("java/lang/RuntimeException"); + if( exClz ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed"); return 0; } OVERLAPPED *overlapped = new OVERLAPPED(); overlapped->hEvent = CreateEventA(NULL, true, false, NULL); - if(WriteFile(hComm, jBuffer, (DWORD)env->GetArrayLength(buffer), &lpNumberOfBytesWritten, overlapped)){ - returnValue = JNI_TRUE; - } - else if(GetLastError() == ERROR_IO_PENDING){ - if(WaitForSingleObject(overlapped->hEvent, INFINITE) == WAIT_OBJECT_0){ - if(GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false)){ - returnValue = JNI_TRUE; - } + DWORD err = 0; + do{ + err = !WriteFile(hComm, jBuffer, (DWORD)env->GetArrayLength(buffer), &lpNumberOfBytesWritten, overlapped); + if( !err ){ /* successfully written. we're already done. */ + returnValue = lpNumberOfBytesWritten; + break; } - } + err = GetLastError(); + if( err != ERROR_IO_PENDING ){ + break; /* some unknown error occurred. Go reporting it. */ + } + /* our write above was async (IO_PENDING). So it was only fired off, but + * we do not know the result yet. Therefore we've to wait for the result. */ + if( WaitForSingleObject(overlapped->hEvent, INFINITE) != WAIT_OBJECT_0 ){ + /* too bad :( wait failed. */ + err = GetLastError(); + break; + } + /* waited successfully. Time to get the result. */ + if( GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false) ){ + /* we know the result now */ + returnValue = lpNumberOfBytesTransferred; + err = 0; + }else{ /* GetOverlappedResult has failed :( */ + err = GetLastError(); + } + }while(0); env->ReleaseByteArrayElements(buffer, jBuffer, 0); CloseHandle(overlapped->hEvent); delete overlapped; + if( err ){ + char emsg[128]; + snprintf(emsg, sizeof emsg, "Error %lu: https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes", (long unsigned)err); + jclass exClz = env->FindClass("java/io/IOException"); + if( exClz ) env->ThrowNew(exClz, emsg); + } return returnValue; } @@ -298,7 +330,7 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer); if( !lpBuffer ){ char emsg[32]; emsg[0] = '\0'; - snprintf(emsg, sizeof emsg, "malloc(%d) failed", byteCount*sizeof*lpBuffer); + snprintf(emsg, sizeof emsg, "malloc(%" PRIsz ") failed", byteCount*sizeof*lpBuffer); jclass exClz = env->FindClass("java/lang/RuntimeException"); if( exClz ) env->ThrowNew(exClz, emsg); returnArray = NULL; goto Finally; diff --git a/src/main/java/jssc/SerialNativeInterface.java b/src/main/java/jssc/SerialNativeInterface.java index 091dc3848..cf6b983b0 100644 --- a/src/main/java/jssc/SerialNativeInterface.java +++ b/src/main/java/jssc/SerialNativeInterface.java @@ -277,7 +277,7 @@ public static String getLibraryVersion() { * * @return If the operation is successfully completed, the method returns true, otherwise false */ - public native boolean writeBytes(long handle, byte[] buffer) throws IOException; + public native int writeBytes(long handle, byte[] buffer) throws IOException; /** * Get bytes count in buffers of port diff --git a/src/main/java/jssc/SerialPort.java b/src/main/java/jssc/SerialPort.java index a203bdec2..6eeae3bb2 100644 --- a/src/main/java/jssc/SerialPort.java +++ b/src/main/java/jssc/SerialPort.java @@ -28,6 +28,8 @@ import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; +import static jssc.SerialPortException.wrapNativeException; + /** * * @author scream3r @@ -404,8 +406,27 @@ public boolean setDTR(boolean enabled) throws SerialPortException { * @return If the operation is successfully completed, the method returns true, otherwise false * * @throws SerialPortException if exception occurred + * + * @deprecated use {@link #writeBytes(byte[])}. + */ + @Deprecated + public boolean writeBytes1(byte[] buffer) throws SerialPortException { + /* Delegate to new method and translate result to what original method + * did return. */ + int numWrittenBytes = writeBytes(buffer); + return numWrittenBytes == buffer.length; + } + + /** + * Write byte array to port. + * + * @param buffer byte[] array to write. + * + * @return number of bytes written. + * + * @throws SerialPortException */ - public boolean writeBytes(byte[] buffer) throws SerialPortException { + public int writeBytes(byte[] buffer) throws SerialPortException { checkPortOpened("writeBytes()"); try { return serialInterface.writeBytes(portHandle, buffer); @@ -427,7 +448,7 @@ public boolean writeBytes(byte[] buffer) throws SerialPortException { */ public boolean writeByte(byte singleByte) throws SerialPortException { checkPortOpened("writeByte()"); - return writeBytes(new byte[]{singleByte}); + return writeBytes(new byte[]{singleByte}) == 1; } /** @@ -443,7 +464,8 @@ public boolean writeByte(byte singleByte) throws SerialPortException { */ public boolean writeString(String string) throws SerialPortException { checkPortOpened("writeString()"); - return writeBytes(string.getBytes()); + byte[] bytes = string.getBytes(); + return writeBytes(bytes) == bytes.length; } /** @@ -460,7 +482,8 @@ public boolean writeString(String string) throws SerialPortException { */ public boolean writeString(String string, String charsetName) throws SerialPortException, UnsupportedEncodingException { checkPortOpened("writeString()"); - return writeBytes(string.getBytes(charsetName)); + byte[] bytes = string.getBytes(charsetName); + return writeBytes(bytes) == bytes.length; } /** @@ -476,7 +499,7 @@ public boolean writeString(String string, String charsetName) throws SerialPortE */ public boolean writeInt(int singleInt) throws SerialPortException { checkPortOpened("writeInt()"); - return writeBytes(new byte[]{(byte)singleInt}); + return writeBytes(new byte[]{(byte)singleInt}) == 1; } /** @@ -496,7 +519,7 @@ public boolean writeIntArray(int[] buffer) throws SerialPortException { for(int i = 0; i < buffer.length; i++){ byteArray[i] = (byte)buffer[i]; } - return writeBytes(byteArray); + return writeBytes(byteArray) == byteArray.length; } /** @@ -1415,4 +1438,5 @@ public void run() { } } } + } From 64c3610a6cf0e2430211163c3473128a66fcbdd0 Mon Sep 17 00:00:00 2001 From: "Andreas Fankhauser hiddenalpha.ch" <23085769+hiddenalpha@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:20:04 +0200 Subject: [PATCH 2/2] Apply PR feedback - Drop legacy function `writeBytes1()` https://github.com/java-native/jssc/pull/195#discussion_r2237037444 - Add superfluous comment as requested https://github.com/java-native/jssc/pull/195#discussion_r2237009596 - Also change all the other `write..` related calls to `int` https://github.com/java-native/jssc/pull/195#discussion_r2237054271 Edit: - Add back "jssc_SerialNativeInterface.h" again (copy-paste as generated from build) https://github.com/java-native/jssc/pull/195#discussion_r2240078225 - Fix typo. https://github.com/java-native/jssc/pull/195#discussion_r2240083647 https://github.com/java-native/jssc/pull/195#discussion_r2240085829 (wip @ dd6dfea3d1e73e1dd0b3585205bb678b9a42286e) --- src/main/cpp/_nix_based/jssc.cpp | 13 +- src/main/cpp/jssc_SerialNativeInterface.h | 175 ++++++++++++++++++++++ src/main/cpp/windows/jssc.cpp | 1 + src/main/java/jssc/SerialPort.java | 68 ++++----- 4 files changed, 211 insertions(+), 46 deletions(-) create mode 100644 src/main/cpp/jssc_SerialNativeInterface.h diff --git a/src/main/cpp/_nix_based/jssc.cpp b/src/main/cpp/_nix_based/jssc.cpp index db70486f7..d0f931cb0 100644 --- a/src/main/cpp/_nix_based/jssc.cpp +++ b/src/main/cpp/_nix_based/jssc.cpp @@ -60,17 +60,6 @@ #include #include "version.h" -#if defined(_MSC_VER) && _MSC_VER < 1800 -# define PRIsz "Iu" -# define PRIssz "Id" -#elif defined(__MINGW32__) && !defined(__MINGW64__) -# define PRIsz "u" -# define PRIssz "d" -#else -# define PRIsz "zu" -# define PRIssz "zd" -#endif - /* * Get native library version */ @@ -681,7 +670,7 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer); if( !lpBuffer ){ char emsg[32]; emsg[0] = '\0'; - snprintf(emsg, sizeof emsg, "malloc(%" PRIsz ") failed", byteCount*sizeof*lpBuffer); + snprintf(emsg, sizeof emsg, "malloc(%zu) failed", byteCount*sizeof*lpBuffer); jclass exClz = env->FindClass("java/lang/RuntimeException"); if( exClz ) env->ThrowNew(exClz, emsg); returnArray = NULL; goto Finally; diff --git a/src/main/cpp/jssc_SerialNativeInterface.h b/src/main/cpp/jssc_SerialNativeInterface.h new file mode 100644 index 000000000..ded00f413 --- /dev/null +++ b/src/main/cpp/jssc_SerialNativeInterface.h @@ -0,0 +1,175 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class jssc_SerialNativeInterface */ + +#ifndef _Included_jssc_SerialNativeInterface +#define _Included_jssc_SerialNativeInterface +#ifdef __cplusplus +extern "C" { +#endif +#undef jssc_SerialNativeInterface_OS_LINUX +#define jssc_SerialNativeInterface_OS_LINUX 0L +#undef jssc_SerialNativeInterface_OS_WINDOWS +#define jssc_SerialNativeInterface_OS_WINDOWS 1L +#undef jssc_SerialNativeInterface_OS_SOLARIS +#define jssc_SerialNativeInterface_OS_SOLARIS 2L +#undef jssc_SerialNativeInterface_OS_MAC_OS_X +#define jssc_SerialNativeInterface_OS_MAC_OS_X 3L +#undef jssc_SerialNativeInterface_OS_UNKNOWN +#define jssc_SerialNativeInterface_OS_UNKNOWN -1L +#undef jssc_SerialNativeInterface_ERR_PORT_BUSY +#define jssc_SerialNativeInterface_ERR_PORT_BUSY -1LL +#undef jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND +#define jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND -2LL +#undef jssc_SerialNativeInterface_ERR_PERMISSION_DENIED +#define jssc_SerialNativeInterface_ERR_PERMISSION_DENIED -3LL +#undef jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT +#define jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT -4LL +/* + * Class: jssc_SerialNativeInterface + * Method: getNativeLibraryVersion + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jssc_SerialNativeInterface_getNativeLibraryVersion + (JNIEnv *, jclass); + +/* + * Class: jssc_SerialNativeInterface + * Method: openPort + * Signature: (Ljava/lang/String;Z)J + */ +JNIEXPORT jlong JNICALL Java_jssc_SerialNativeInterface_openPort + (JNIEnv *, jobject, jstring, jboolean); + +/* + * Class: jssc_SerialNativeInterface + * Method: setParams + * Signature: (JIIIIZZI)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setParams + (JNIEnv *, jobject, jlong, jint, jint, jint, jint, jboolean, jboolean, jint); + +/* + * Class: jssc_SerialNativeInterface + * Method: purgePort + * Signature: (JI)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_purgePort + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: jssc_SerialNativeInterface + * Method: closePort + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_closePort + (JNIEnv *, jobject, jlong); + +/* + * Class: jssc_SerialNativeInterface + * Method: setEventsMask + * Signature: (JI)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setEventsMask + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: jssc_SerialNativeInterface + * Method: getEventsMask + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getEventsMask + (JNIEnv *, jobject, jlong); + +/* + * Class: jssc_SerialNativeInterface + * Method: waitEvents + * Signature: (J)[[I + */ +JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_waitEvents + (JNIEnv *, jobject, jlong); + +/* + * Class: jssc_SerialNativeInterface + * Method: setRTS + * Signature: (JZ)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setRTS + (JNIEnv *, jobject, jlong, jboolean); + +/* + * Class: jssc_SerialNativeInterface + * Method: setDTR + * Signature: (JZ)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR + (JNIEnv *, jobject, jlong, jboolean); + +/* + * Class: jssc_SerialNativeInterface + * Method: readBytes + * Signature: (JI)[B + */ +JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: jssc_SerialNativeInterface + * Method: writeBytes + * Signature: (J[B)I + */ +JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_writeBytes + (JNIEnv *, jobject, jlong, jbyteArray); + +/* + * Class: jssc_SerialNativeInterface + * Method: getBuffersBytesCount + * Signature: (J)[I + */ +JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getBuffersBytesCount + (JNIEnv *, jobject, jlong); + +/* + * Class: jssc_SerialNativeInterface + * Method: setFlowControlMode + * Signature: (JI)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setFlowControlMode + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: jssc_SerialNativeInterface + * Method: getFlowControlMode + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getFlowControlMode + (JNIEnv *, jobject, jlong); + +/* + * Class: jssc_SerialNativeInterface + * Method: getSerialPortNames + * Signature: ()[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_getSerialPortNames + (JNIEnv *, jobject); + +/* + * Class: jssc_SerialNativeInterface + * Method: getLinesStatus + * Signature: (J)[I + */ +JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getLinesStatus + (JNIEnv *, jobject, jlong); + +/* + * Class: jssc_SerialNativeInterface + * Method: sendBreak + * Signature: (JI)Z + */ +JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_sendBreak + (JNIEnv *, jobject, jlong, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/main/cpp/windows/jssc.cpp b/src/main/cpp/windows/jssc.cpp index 45c163d99..755a003a8 100644 --- a/src/main/cpp/windows/jssc.cpp +++ b/src/main/cpp/windows/jssc.cpp @@ -29,6 +29,7 @@ #include #include "version.h" +// For snprintf formatting #if defined(_MSC_VER) && _MSC_VER < 1800 # define PRIsz "Iu" # define PRIssz "Id" diff --git a/src/main/java/jssc/SerialPort.java b/src/main/java/jssc/SerialPort.java index 6eeae3bb2..a417cd058 100644 --- a/src/main/java/jssc/SerialPort.java +++ b/src/main/java/jssc/SerialPort.java @@ -398,25 +398,6 @@ public boolean setDTR(boolean enabled) throws SerialPortException { return serialInterface.setDTR(portHandle, enabled); } - /** - * Write byte array to port - * - * @param buffer byte[] array to write - * - * @return If the operation is successfully completed, the method returns true, otherwise false - * - * @throws SerialPortException if exception occurred - * - * @deprecated use {@link #writeBytes(byte[])}. - */ - @Deprecated - public boolean writeBytes1(byte[] buffer) throws SerialPortException { - /* Delegate to new method and translate result to what original method - * did return. */ - int numWrittenBytes = writeBytes(buffer); - return numWrittenBytes == buffer.length; - } - /** * Write byte array to port. * @@ -440,15 +421,15 @@ public int writeBytes(byte[] buffer) throws SerialPortException { * * @param singleByte single byte value to write * - * @return If the operation is successfully completed, the method returns true, otherwise false + * @return Number of bytes written. * * @throws SerialPortException if exception occurred * * @since 0.8 */ - public boolean writeByte(byte singleByte) throws SerialPortException { + public int writeByte(byte singleByte) throws SerialPortException { checkPortOpened("writeByte()"); - return writeBytes(new byte[]{singleByte}) == 1; + return writeBytes(new byte[]{singleByte}); } /** @@ -456,16 +437,25 @@ public boolean writeByte(byte singleByte) throws SerialPortException { * * @param string String value to write * - * @return If the operation is successfully completed, the method returns true, otherwise false + * @return + * Number of bytes written. WARN: Number of BYTES, NOT number of CHARS! + * This may differ from string.length() if passed in string + * contains chars outside the english alphabet. If you need reliable + * return lengths, consider calling + * {@link java.lang.String#getBytes(java.nio.charset.Charset)} + * yourself and then passing result to + * {@link #writeBytes(byte[])} + * instead. This gives you the chance to verify the expected return + * value correctly. * * @throws SerialPortException if exception occurred * * @since 0.8 */ - public boolean writeString(String string) throws SerialPortException { + public int writeString(String string) throws SerialPortException { checkPortOpened("writeString()"); byte[] bytes = string.getBytes(); - return writeBytes(bytes) == bytes.length; + return writeBytes(bytes); } /** @@ -473,17 +463,27 @@ public boolean writeString(String string) throws SerialPortException { * * @param string String value to write * @param charsetName valid Charset name, e.g. "UTF-8" - * @return If the operation is successfully completed, the method returns true, otherwise false + * + * @return + * Number of bytes written. WARN: Number of BYTES, NOT number of CHARS! + * This may differ from string.length() if passed in string + * contains chars outside the english alphabet. If you need reliable + * return lengths, consider calling + * {@link java.lang.String#getBytes(java.nio.charset.Charset)} + * yourself and then passing result to + * {@link #writeBytes(byte[])} + * instead. This gives you the chance to verify the expected return + * value correctly. * * @throws SerialPortException if exception occurred * @throws UnsupportedEncodingException if encoding exception occurred * * @since 2.8.0 */ - public boolean writeString(String string, String charsetName) throws SerialPortException, UnsupportedEncodingException { + public int writeString(String string, String charsetName) throws SerialPortException, UnsupportedEncodingException { checkPortOpened("writeString()"); byte[] bytes = string.getBytes(charsetName); - return writeBytes(bytes) == bytes.length; + return writeBytes(bytes); } /** @@ -491,15 +491,15 @@ public boolean writeString(String string, String charsetName) throws SerialPortE * * @param singleInt single int value to write * - * @return If the operation is successfully completed, the method returns true, otherwise false + * @return Number of bytes written. * * @throws SerialPortException if exception occurred * * @since 0.8 */ - public boolean writeInt(int singleInt) throws SerialPortException { + public int writeInt(int singleInt) throws SerialPortException { checkPortOpened("writeInt()"); - return writeBytes(new byte[]{(byte)singleInt}) == 1; + return writeBytes(new byte[]{(byte)singleInt}); } /** @@ -507,19 +507,19 @@ public boolean writeInt(int singleInt) throws SerialPortException { * * @param buffer int[] array to write * - * @return If the operation is successfully completed, the method returns true, otherwise false + * @return Number of bytes written. * * @throws SerialPortException if exception occurred * * @since 0.8 */ - public boolean writeIntArray(int[] buffer) throws SerialPortException { + public int writeIntArray(int[] buffer) throws SerialPortException { checkPortOpened("writeIntArray()"); byte[] byteArray = new byte[buffer.length]; for(int i = 0; i < buffer.length; i++){ byteArray[i] = (byte)buffer[i]; } - return writeBytes(byteArray) == byteArray.length; + return writeBytes(byteArray); } /**