Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions src/main/cpp/_nix_based/jssc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <time.h>
Expand All @@ -40,7 +39,6 @@
#endif
#ifdef __sun
#include <sys/filio.h>//Needed for FIONREAD in Solaris
#include <string.h>//Needed for select() function
#endif
#ifdef __APPLE__
#include <serial/ioss.h>//Needed for IOSSIOSPEED in Mac OS X (Non standard baudrate)
Expand All @@ -62,8 +60,6 @@
#include <jssc_SerialNativeInterface.h>
#include "version.h"

//#include <iostream> //-lCstd use for Solaris linker

/*
* Get native library version
*/
Expand Down Expand Up @@ -529,33 +525,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;
}

/**
Expand Down Expand Up @@ -676,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(%d) 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;
Expand Down
8 changes: 5 additions & 3 deletions src/main/cpp/jssc_SerialNativeInterface.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 52 additions & 19 deletions src/main/cpp/windows/jssc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,17 @@
#include <jssc_SerialNativeInterface.h>
#include "version.h"

//#include <iostream>
// For snprintf formatting
#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

Expand Down Expand Up @@ -232,38 +242,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;
}

Expand Down Expand Up @@ -298,7 +331,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;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/jssc/SerialNativeInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
60 changes: 42 additions & 18 deletions src/main/java/jssc/SerialPort.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;

import static jssc.SerialPortException.wrapNativeException;

/**
*
* @author scream3r
Expand Down Expand Up @@ -397,15 +399,15 @@ public boolean setDTR(boolean enabled) throws SerialPortException {
}

/**
* Write byte array to port
* Write byte array to port.
*
* @param buffer <code>byte[]</code> array to write
* @param buffer <code>byte[]</code> array to write.
*
* @return If the operation is successfully completed, the method returns true, otherwise false
*
* @throws SerialPortException if exception occurred
* @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);
Expand All @@ -419,13 +421,13 @@ public boolean writeBytes(byte[] buffer) throws SerialPortException {
*
* @param singleByte single <code>byte</code> 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});
}
Expand All @@ -435,46 +437,67 @@ public boolean writeByte(byte singleByte) throws SerialPortException {
*
* @param string <code>String</code> 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 <code>string.length()</code> 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()");
return writeBytes(string.getBytes());
byte[] bytes = string.getBytes();
return writeBytes(bytes);
}

/**
* Write String to port
*
* @param string <code>String</code> value to write
* @param charsetName valid <code>Charset</code> name, e.g. <code>"UTF-8"</code>
* @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 <code>string.length()</code> 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()");
return writeBytes(string.getBytes(charsetName));
byte[] bytes = string.getBytes(charsetName);
return writeBytes(bytes);
}

/**
* Write int value (in range from 0 to 255 (0x00 - 0xFF)) to port
*
* @param singleInt single <code>int</code> 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});
}
Expand All @@ -484,13 +507,13 @@ public boolean writeInt(int singleInt) throws SerialPortException {
*
* @param buffer <code>int[]</code> 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++){
Expand Down Expand Up @@ -1415,4 +1438,5 @@ public void run() {
}
}
}

}
Loading