Skip to content

Commit a7ec5da

Browse files
committed
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: - #129 (wip @ 17cc247)
1 parent 4b167f2 commit a7ec5da

File tree

5 files changed

+110
-222
lines changed

5 files changed

+110
-222
lines changed

src/main/cpp/_nix_based/jssc.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include <stdlib.h>
3030
#include <string.h>
3131
#include <unistd.h>
32-
#include <string.h>
3332
#include <sys/ioctl.h>
3433
#include <termios.h>
3534
#include <time.h>
@@ -40,7 +39,6 @@
4039
#endif
4140
#ifdef __sun
4241
#include <sys/filio.h>//Needed for FIONREAD in Solaris
43-
#include <string.h>//Needed for select() function
4442
#endif
4543
#ifdef __APPLE__
4644
#include <serial/ioss.h>//Needed for IOSSIOSPEED in Mac OS X (Non standard baudrate)
@@ -62,7 +60,16 @@
6260
#include <jssc_SerialNativeInterface.h>
6361
#include "version.h"
6462

65-
//#include <iostream> //-lCstd use for Solaris linker
63+
#if defined(_MSC_VER) && _MSC_VER < 1800
64+
# define PRIsz "Iu"
65+
# define PRIssz "Id"
66+
#elif defined(__MINGW32__) && !defined(__MINGW64__)
67+
# define PRIsz "u"
68+
# define PRIssz "d"
69+
#else
70+
# define PRIsz "zu"
71+
# define PRIssz "zd"
72+
#endif
6673

6774
/*
6875
* Get native library version
@@ -529,33 +536,31 @@ JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR
529536
/*
530537
* Writing data to the port
531538
*/
532-
JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes
539+
JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_writeBytes
533540
(JNIEnv *env, jobject, jlong portHandle, jbyteArray buffer){
534-
if( buffer == NULL ){
541+
ssize_t ret = 0;
542+
jbyte *jBuffer = NULL;
543+
if( !buffer ){
535544
jclass exClz = env->FindClass("java/lang/NullPointerException");
536-
if( exClz != NULL ) env->ThrowNew(exClz, "buffer");
537-
return 0;
545+
if( exClz ) env->ThrowNew(exClz, "buffer");
546+
goto Finally;
538547
}
539-
jboolean ret = JNI_FALSE;
540-
jbyte* jBuffer = env->GetByteArrayElements(buffer, JNI_FALSE);
541-
if( jBuffer == NULL ){
542-
jclass exClz = env->FindClass("java/lang/RuntimeException");
543-
if( exClz != NULL ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed");
544-
return 0;
548+
jBuffer = env->GetByteArrayElements(buffer, NULL);
549+
if( !jBuffer ){
550+
jclass exClz = env->ExceptionCheck() ? NULL : env->FindClass("java/lang/RuntimeException");
551+
if( exClz ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed");
552+
goto Finally;
545553
}
546-
jint bufferSize = env->GetArrayLength(buffer);
547-
jint result = write(portHandle, jBuffer, (size_t)bufferSize);
548-
if( result == -1 ){
549-
int err = errno; /*bakup errno*/
554+
ret = write(portHandle, jBuffer, env->GetArrayLength(buffer));
555+
if( ret == -1 ){
556+
int err = errno;
550557
jclass exClz = env->FindClass("java/io/IOException");
551-
assert(exClz != NULL);
552-
env->ThrowNew(exClz, strerror(err));
558+
if( exClz ) env->ThrowNew(exClz, strerror(err));
553559
goto Finally;
554560
}
555-
ret = (result == bufferSize) ? JNI_TRUE : JNI_FALSE;
556561
Finally:
557-
env->ReleaseByteArrayElements(buffer, jBuffer, 0);
558-
return ret;
562+
if( jBuffer ) env->ReleaseByteArrayElements(buffer, jBuffer, 0);
563+
return (jint)ret;
559564
}
560565

561566
/**
@@ -676,7 +681,7 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes
676681
lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer);
677682
if( !lpBuffer ){
678683
char emsg[32]; emsg[0] = '\0';
679-
snprintf(emsg, sizeof emsg, "malloc(%d) failed", byteCount*sizeof*lpBuffer);
684+
snprintf(emsg, sizeof emsg, "malloc(%" PRIsz ") failed", byteCount*sizeof*lpBuffer);
680685
jclass exClz = env->FindClass("java/lang/RuntimeException");
681686
if( exClz ) env->ThrowNew(exClz, emsg);
682687
returnArray = NULL; goto Finally;

src/main/cpp/jssc_SerialNativeInterface.h

Lines changed: 0 additions & 173 deletions
This file was deleted.

src/main/cpp/windows/jssc.cpp

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,16 @@
2929
#include <jssc_SerialNativeInterface.h>
3030
#include "version.h"
3131

32-
//#include <iostream>
32+
#if defined(_MSC_VER) && _MSC_VER < 1800
33+
# define PRIsz "Iu"
34+
# define PRIssz "Id"
35+
#elif defined(__MINGW32__) && !defined(__MINGW64__)
36+
# define PRIsz "u"
37+
# define PRIssz "d"
38+
#else
39+
# define PRIsz "zu"
40+
# define PRIssz "zd"
41+
#endif
3342

3443
#define MAX_PORT_NAME_STR_LEN 32
3544

@@ -232,38 +241,61 @@ JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR
232241
* portHandle - port handle
233242
* buffer - byte array for sending
234243
*/
235-
JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes
244+
JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_writeBytes
236245
(JNIEnv *env, jobject, jlong portHandle, jbyteArray buffer){
237246
HANDLE hComm = (HANDLE)portHandle;
238247
DWORD lpNumberOfBytesTransferred;
239248
DWORD lpNumberOfBytesWritten;
240-
jboolean returnValue = JNI_FALSE;
241-
if( buffer == NULL ){
249+
jint returnValue = -1;
250+
if( !buffer ){
242251
jclass exClz = env->FindClass("java/lang/NullPointerException");
243-
if( exClz != NULL ) env->ThrowNew(exClz, "buffer");
252+
if( exClz ) env->ThrowNew(exClz, "buffer");
244253
return 0;
245254
}
246-
jbyte* jBuffer = env->GetByteArrayElements(buffer, JNI_FALSE);
247-
if( jBuffer == NULL ){
248-
jclass exClz = env->FindClass("java/lang/RuntimeException");
249-
if( exClz != NULL ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed");
255+
jbyte *jBuffer = env->GetByteArrayElements(buffer, NULL);
256+
if( !jBuffer ){
257+
jclass exClz = env->ExceptionCheck() ? NULL : env->FindClass("java/lang/RuntimeException");
258+
if( exClz ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed");
250259
return 0;
251260
}
252261
OVERLAPPED *overlapped = new OVERLAPPED();
253262
overlapped->hEvent = CreateEventA(NULL, true, false, NULL);
254-
if(WriteFile(hComm, jBuffer, (DWORD)env->GetArrayLength(buffer), &lpNumberOfBytesWritten, overlapped)){
255-
returnValue = JNI_TRUE;
256-
}
257-
else if(GetLastError() == ERROR_IO_PENDING){
258-
if(WaitForSingleObject(overlapped->hEvent, INFINITE) == WAIT_OBJECT_0){
259-
if(GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false)){
260-
returnValue = JNI_TRUE;
261-
}
263+
DWORD err = 0;
264+
do{
265+
err = !WriteFile(hComm, jBuffer, (DWORD)env->GetArrayLength(buffer), &lpNumberOfBytesWritten, overlapped);
266+
if( !err ){ /* successfully written. we're already done. */
267+
returnValue = lpNumberOfBytesWritten;
268+
break;
262269
}
263-
}
270+
err = GetLastError();
271+
if( err != ERROR_IO_PENDING ){
272+
break; /* some unknown error occurred. Go reporting it. */
273+
}
274+
/* our write above was async (IO_PENDING). So it was only fired off, but
275+
* we do not know the result yet. Therefore we've to wait for the result. */
276+
if( WaitForSingleObject(overlapped->hEvent, INFINITE) != WAIT_OBJECT_0 ){
277+
/* too bad :( wait failed. */
278+
err = GetLastError();
279+
break;
280+
}
281+
/* waited successfully. Time to get the result. */
282+
if( GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false) ){
283+
/* we know the result now */
284+
returnValue = lpNumberOfBytesTransferred;
285+
err = 0;
286+
}else{ /* GetOverlappedResult has failed :( */
287+
err = GetLastError();
288+
}
289+
}while(0);
264290
env->ReleaseByteArrayElements(buffer, jBuffer, 0);
265291
CloseHandle(overlapped->hEvent);
266292
delete overlapped;
293+
if( err ){
294+
char emsg[128];
295+
snprintf(emsg, sizeof emsg, "Error %lu: https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes", (long unsigned)err);
296+
jclass exClz = env->FindClass("java/io/IOException");
297+
if( exClz ) env->ThrowNew(exClz, emsg);
298+
}
267299
return returnValue;
268300
}
269301

@@ -298,7 +330,7 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes
298330
lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer);
299331
if( !lpBuffer ){
300332
char emsg[32]; emsg[0] = '\0';
301-
snprintf(emsg, sizeof emsg, "malloc(%d) failed", byteCount*sizeof*lpBuffer);
333+
snprintf(emsg, sizeof emsg, "malloc(%" PRIsz ") failed", byteCount*sizeof*lpBuffer);
302334
jclass exClz = env->FindClass("java/lang/RuntimeException");
303335
if( exClz ) env->ThrowNew(exClz, emsg);
304336
returnArray = NULL; goto Finally;

src/main/java/jssc/SerialNativeInterface.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ public static String getLibraryVersion() {
277277
*
278278
* @return If the operation is successfully completed, the method returns true, otherwise false
279279
*/
280-
public native boolean writeBytes(long handle, byte[] buffer) throws IOException;
280+
public native int writeBytes(long handle, byte[] buffer) throws IOException;
281281

282282
/**
283283
* Get bytes count in buffers of port

0 commit comments

Comments
 (0)