Lots of updates/fixes. Finished updating Windows.

This commit is contained in:
hedgecrw85 2015-03-09 15:51:09 -05:00
parent 93f7d9202f
commit 24488d2a91
26 changed files with 479 additions and 92 deletions

108
INSTALL
View File

@ -1,31 +1,119 @@
-------------
ALL SYSTEMS
-------------
----------
BUILDING
----------
Make sure proper JDK version installed for backward compatibility, targeting Java 1.6 (JDK 1.6)
Building this library yourself is not advised (at least not for distribution) since it requires native compilation across multiple platforms. It is recommended to simply use the pre-built jSerialComm library in your application. For installation/usage instructions, please skip ahead to the "USAGE" section.
On any OS, make sure JDK_HOME is set
If you do choose to build this library for your specific system, the recommended methodology is to use Gradle coupled with the Java SDK, version 1.6 (for backward compatibility).
Java SDK 1.6 can be downloaded from http://www.oracle.com/technetwork/java/archive-139210.html
Gradle can be downloaded from https://gradle.org/
Once the Java SDK 1.6 has been installed, ensure that you have an environment variable called JDK_HOME set to the base directory of your JDK installation. Once this has been done, refer to the section corresponding to your specific Operating System for further instructions.
Please note, if you would like to edit any of the source code or view it in an IDE (such as Eclipse), you can automatically build the Eclipse project files by entering the following on a command line or terminal from the base directory of this project (.../jSerialComm/): gradle eclipse
You can then Import the project using the "Existing Project into Workspace" import tool in Eclipse. (Note that if you use Eclipse as an IDE, you will probably want to install the CDT plugin (http:....) for proper handling of the C/C++ source code)
------------
LINUX/UNIX
------------
g++ make glibc-devel.x86_64 glibc-devel.i686 libstdc++-devel.x86_64 libstdc++-devel.i686
Ensure that the following tools are installed on your Linux distribution: g++ make glibc-devel.x86_64 glibc-devel.i686 libstdc++-devel.x86_64 libstdc++-devel.i686
readlink -f /usr/bin/java : export everything up to /jre/... Ex: export JDK_HOME=/usr/lib/jvm/java-1.6.0-openjdk.x86_64
Ensure that the JDK_HOME environment variable has been set for the 1.6 version of your Java SDK. The correct directory can usually be found by entering the following command: readlink -f /usr/bin/java
Export the result of this command UP TO BUT NOT INCLUDING the /jre/... portion using the 'export' command. For example, if 'readlink' produced "/usr/lib/jvm/java-6-jdk/jre/bin/java" as an output, the export command would look like: export JDK_HOME=/usr/lib/jvm/java-6-jdk
Change directories to the following project directory: ".../jSerialComm/src/main/cpp/Linux/"
Run the following commands in order:
make
cd ../../../..
gradle build
The resulting jSerialComm library can be found in the project directory ".../jSerialComm/build/libs/" under the name "jSerialComm-{VERSION}.jar"
----------
MAC OS X
----------
Ensure that Xcode is installed on your system. If it is not, it can be downloaded via the App Store.
Ensure that the JDK_HOME environment variable has been set for the 1.6 version of your Java SDK. The correct directory can usually be found by entering the following command: readlink -f /usr/bin/java
Export the result of this command UP TO BUT NOT INCLUDING the /jre/... portion using the 'export' command. For example, if 'readlink' produced "/usr/lib/jvm/java-6-jdk/jre/bin/java" as an output, the export command would look like: export JDK_HOME=/usr/lib/jvm/java-6-jdk
Change directories to the following project directory: ".../jSerialComm/src/main/cpp/OSX/"
Run the following commands in order:
make
cd ../../../..
gradle build
The resulting jSerialComm library can be found in the project directory ".../jSerialComm/build/libs/" under the name "jSerialComm-{VERSION}.jar"
---------
WINDOWS
---------
First, call C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat" x64 or x86 before building
Ensure that the Visual Studio C++ Compiler is installed on your system. If it is not, you can download a free version (Visual C++ 2010 Express) from https://www.visualstudio.com/downloads/download-visual-studio-vs.
Open up a command prompt (Run->'cmd') and change to the following project directory: "...\jSerialComm\src\main\cpp\Windows\"
On Windows, the Visual Studio Compiler must be configured to build either 32- or 64-bit binaries but never both at the same time. Therefore, you will have to build binaries for the two architectures separately.
For the following commands, {VC_DIRECTORY} is the installation directory of your Visual Studio C++ Compiler (for example: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC). Run the following commands in order:
gradle eclipse
{VC_DIRECTORY}\vcvarsall.bat x64
nmake win64
{VC_DIRECTORY}\vcvarsall.bat x86
nmake win32
cd ..\..\..\..
gradle build
Located in build/lib
The resulting jSerialComm library can be found in the project directory "...\jSerialComm\build\libs\" under the name "jSerialComm-{VERSION}.jar"
-------
USAGE
-------
In order to use the jSerialComm library in your own project, you must simply include the jSerialComm JAR file in your build path and import it like any other java package using "import com.fazecast.jSerialComm.*;"
Alternatively, you can automatically add jSerialComm to your project as a dependency from the Maven Central Repository. Use the following dependency declaration depending on your build system:
Maven:
<dependency>
<groupId>com.fazecast.jSerialComm</groupId>
<artifactId>jSerialComm</artifactId>
<version>1.0.0</version>
</dependency>
Ivy:
<dependency org="com.fazecast.jSerialComm" name="jSerialComm" rev="1.0.0"/>
Grape:
@Grapes(
@Grab(group='com.fazecast.jSerialComm', module='jSerialComm', version='1.0.0')
)
Gradle:
'com.fazecast.jSerialComm:jSerialComm:1.0.0'
Buildr:
'com.fazecast.jSerialComm:jSerialComm:jar:1.0.0'
SBT:
libraryDependencies += "com.fazecast.jSerialComm" % "jSerialComm" % "1.0.0"
Leiningen:
[com.fazecast.jSerialComm/jSerialComm "1.0.0"]

11
README
View File

@ -1,2 +1,9 @@
# jSerialComm
Platform-independent serial port access for Java
------------------------------------------------------------
jSerialComm
------------
A platform-independent serial port access library for Java
------------------------------------------------------------
For building and/or installation instructions, please refer to the INSTALL file
For usage examples, please refer to the Usage Wiki at https://github.com/Fazecast/jSerialComm/wiki/Usage-Examples

View File

@ -9,6 +9,7 @@ version = '1.0.0'
sourceCompatibility = 1.6
targetCompatibility = 1.6
javadoc.options.links("http://docs.oracle.com/javase/7/docs/api/")
//compileJava.options.bootClasspath = "C:/Program Files/Java/jre6/lib/rt.jar"
jar {

View File

@ -17,8 +17,7 @@ JFLAGS := -source 1.6 -target 1.6 -Xlint:-options
LIBRARY_NAME := libjSerialComm.so
SOURCES := SerialPort_Linux.cpp
JAVA_SOURCE_DIR = ../../../../src/main/java/com/fazecast/jSerialComm
RESOURCE_DIR1 = ../../../../src/main/resources/Linux
RESOURCE_DIR2 = ../../../../src/test/resources/Linux
RESOURCE_DIR = ../../../../src/main/resources/Linux
BUILD_DIR = ../../../../bin/Linux
JAVA_CLASS_DIR = $(BUILD_DIR)/../com/fazecast/jSerialComm
OBJECTSx86 = $(BUILD_DIR)/x86/$(SOURCES:.cpp=.o)
@ -40,15 +39,13 @@ all : linux32 linux64
linux32 : ARCH = -m32
linux32 : checkdirs $(BUILD_DIR)/x86/$(LIBRARY_NAME)
$(DELETE) -rf $(BUILD_DIR)/x86/*.o
$(COPY) $(BUILD_DIR)/x86/*.* $(RESOURCE_DIR1)/x86
$(MOVE) $(BUILD_DIR)/x86/*.* $(RESOURCE_DIR2)/x86
$(COPY) $(BUILD_DIR)/x86/*.* $(RESOURCE_DIR)/x86
# Builds 64-bit Linux libraries
linux64 : ARCH = -m64
linux64 : checkdirs $(BUILD_DIR)/x86_64/$(LIBRARY_NAME)
$(DELETE) -rf $(BUILD_DIR)/x86_64/*.o
$(COPY) $(BUILD_DIR)/x86_64/*.* $(RESOURCE_DIR1)/x86_64
$(MOVE) $(BUILD_DIR)/x86_64/*.* $(RESOURCE_DIR2)/x86_64
$(COPY) $(BUILD_DIR)/x86_64/*.* $(RESOURCE_DIR)/x86_64
# Rule to create build directories
checkdirs : $(BUILD_DIR)/x86 $(BUILD_DIR)/x86_64 $(JAVA_CLASS_DIR)
@ -79,4 +76,4 @@ $(JNI_HEADER) : $(JAVA_CLASS)
# Suffix rule to get from *.java -> *.class
$(JAVA_CLASS) :
$(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)/../../.. $(JAVA_SOURCE_DIR)/$(basename $(notdir $@)).java
$(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)/../../.. -cp $(JAVA_SOURCE_DIR)/../../.. $(JAVA_SOURCE_DIR)/$(basename $(notdir $@)).java

View File

@ -99,7 +99,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNati
// Configure the port parameters and timeouts
if (Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj) && Java_com_fazecast_jSerialComm_SerialPort_configFlowControl(env, obj) &&
Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj))
Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj))
env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_TRUE);
else
{

View File

@ -17,8 +17,7 @@ JFLAGS := -source 1.6 -target 1.6 -Xlint:-options
LIBRARY_NAME := libjSerialComm.jnilib
SOURCES := SerialPort_OSX.cpp
JAVA_SOURCE_DIR = ../../../../src/main/java/com/fazecast/jSerialComm
RESOURCE_DIR1 = ../../../../src/main/resources/OSX
RESOURCE_DIR2 = ../../../../src/test/resources/OSX
RESOURCE_DIR = ../../../../src/main/resources/OSX
BUILD_DIR = ../../../../bin/OSX
JAVA_CLASS_DIR = $(BUILD_DIR)/../com/fazecast/jSerialComm
OBJECTSx86 = $(BUILD_DIR)/x86/$(SOURCES:.cpp=.o)
@ -40,15 +39,13 @@ all : osx32 osx64
osx32 : ARCH = -m32
osx32 : checkdirs $(BUILD_DIR)/x86/$(LIBRARY_NAME)
$(DELETE) -rf $(BUILD_DIR)/x86/*.o
$(COPY) $(BUILD_DIR)/x86/*.* $(RESOURCE_DIR1)/x86
$(MOVE) $(BUILD_DIR)/x86/*.* $(RESOURCE_DIR2)/x86
$(COPY) $(BUILD_DIR)/x86/*.* $(RESOURCE_DIR)/x86
# Builds 64-bit OSX libraries
osx64 : ARCH = -m64
osx64 : checkdirs $(BUILD_DIR)/x86_64/$(LIBRARY_NAME)
$(DELETE) -rf $(BUILD_DIR)/x86_64/*.o
$(COPY) $(BUILD_DIR)/x86_64/*.* $(RESOURCE_DIR1)/x86_64
$(MOVE) $(BUILD_DIR)/x86_64/*.* $(RESOURCE_DIR2)/x86_64
$(COPY) $(BUILD_DIR)/x86_64/*.* $(RESOURCE_DIR)/x86_64
# Rule to create build directories
checkdirs : $(BUILD_DIR)/x86 $(BUILD_DIR)/x86_64 $(JAVA_CLASS_DIR)
@ -79,4 +76,4 @@ $(JNI_HEADER) : $(JAVA_CLASS)
# Suffix rule to get from *.java -> *.class
$(JAVA_CLASS) :
$(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)/../../.. $(JAVA_SOURCE_DIR)/$(basename $(notdir $@)).java
$(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)/../../.. -cp $(JAVA_SOURCE_DIR)/../../.. $(JAVA_SOURCE_DIR)/$(basename $(notdir $@)).java

View File

@ -95,7 +95,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNati
// Configure the port parameters and timeouts
if (Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj) && Java_com_fazecast_jSerialComm_SerialPort_configFlowControl(env, obj) &&
Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj))
Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj))
env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_TRUE);
else
{

View File

@ -6,85 +6,82 @@ LDFLAGS = /DLL /LTCG /NOASSEMBLY /NOLOGO
INCLUDES = /I"$(JDK_HOME)/include" /I"$(JDK_HOME)/include/win32"
LIBRARIES = Advapi32.lib
DELETE = @del /q /f
RMDIR = @rmdir /q /s
MKDIR = @mkdir
RMDIR = @rd /q /s
MKDIR = @md
COPY = @copy /y
MOVE = @move /y
PRINT = @echo
FULL_CLASS = com.fazecast.jSerialComm.SerialPort
JAVAC = "$(JDK_HOME)/bin/javac"
JAVAH = "$(JDK_HOME)/bin/javah" -jni
JAVAC = "$(JDK_HOME)\bin\javac"
JAVAH = "$(JDK_HOME)\bin\javah" -jni
JFLAGS = -source 1.6 -target 1.6 -Xlint:-options
LIBRARY_NAME = jSerialComm.dll
SOURCES = SerialPort_Windows.cpp
JAVA_SOURCE_DIR = ../../../../src/main/java/com/fazecast/jSerialComm
RESOURCE_DIR1 = ../../../../src/main/resources/Windows
RESOURCE_DIR2 = ../../../../src/test/resources/Windows
BUILD_DIR = ../../../../bin/Windows
JAVA_CLASS_DIR = $(BUILD_DIR)/../com/fazecast/jSerialComm
OBJECTSx86 = $(BUILD_DIR)/x86/$(SOURCES:.cpp=.o)
OBJECTSx86_64 = $(BUILD_DIR)/x86_64/$(SOURCES:.cpp=.o)
JNI_HEADER = ../com_fazecast_jSerialComm_SerialPort.h
JAVA_CLASS = $(JAVA_CLASS_DIR)/SerialPort.class
JAVA_SOURCE_DIR = ..\..\..\..\src\main\java\com\fazecast\jSerialComm
RESOURCE_DIR = ..\..\..\..\src\main\resources\Windows
BUILD_DIR = ..\..\..\..\bin\Windows
JAVA_CLASS_DIR = $(BUILD_DIR)\..\com\fazecast\jSerialComm
OBJECTSx86 = $(BUILD_DIR)\x86\$(SOURCES:.cpp=.obj)
OBJECTSx86_64 = $(BUILD_DIR)\x86_64\$(SOURCES:.cpp=.obj)
JNI_HEADER = ..\com_fazecast_jSerialComm_SerialPort.h
JAVA_CLASS = $(JAVA_CLASS_DIR)\SerialPort.class
# Define phony and suffix rules
.PHONY: all win32 win64 checkdirs clean
.SUFFIXES:
.SUFFIXES: .cpp .o .class .java .h
.SUFFIXES: .cpp .obj .class .java .h
# Default build target not possible due to different architecture compilers
all :
$(PRINT).
$(PRINT) Must specify a target (either win32 or win64), but not both at the same time since different versions of the Microsoft Compiler are required for difference architectures.
$(PRINT).
$(PRINT) NOTE: Before attempting to use this Makefile, make sure that you have called 'vcvarsall.bat' for your intended architecture. This file can normally be found in "C:/Program Files (x86)/Microsoft Visual Studio [version]/VC/".
$(PRINT) NOTE: Before attempting to use this Makefile, make sure that you have called 'vcvarsall.bat' for your intended architecture. This file can normally be found in "C:\Program Files (x86)\Microsoft Visual Studio [version]\VC\".
$(PRINT).
$(PRINT) Example: To build 64-bit Windows libraries, you would call:
$(PRINT) C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat x64
$(PRINT) mingw32-make
$(PRINT) C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat x64
$(PRINT) nmake
$(PRINT).
# Builds 32-bit Windows libraries
win32 : checkdirs $(BUILD_DIR)/x86/$(LIBRARY_NAME)
$(DELETE) "$(BUILD_DIR)"\\x86\\*.o
$(COPY) "$(BUILD_DIR)"\\x86\\*.* "$(RESOURCE_DIR1)"\\x86
$(MOVE) "$(BUILD_DIR)"\\x86\\*.* "$(RESOURCE_DIR2)"\\x86
$(DELETE) ".."\\*.h
$(RMDIR) "$(BUILD_DIR)/.."
win32 : checkdirs $(BUILD_DIR)\x86\$(LIBRARY_NAME)
$(DELETE) $(BUILD_DIR)\x86\*.obj
$(COPY) $(BUILD_DIR)\x86\*.* $(RESOURCE_DIR)\x86
$(DELETE) ..\*.h
$(RMDIR) $(BUILD_DIR)\..
# Builds 64-bit Windows libraries
win64 : checkdirs $(BUILD_DIR)/x86_64/$(LIBRARY_NAME)
$(DELETE) "$(BUILD_DIR)"\\x86_64\\*.o
$(COPY) "$(BUILD_DIR)"\\x86_64\\*.* "$(RESOURCE_DIR1)"\\x86_64
$(MOVE) "$(BUILD_DIR)"\\x86_64\\*.* "$(RESOURCE_DIR2)"\\x86_64
$(DELETE) ".."\\*.h
$(RMDIR) "$(BUILD_DIR)/.."
win64 : checkdirs $(BUILD_DIR)\x86_64\$(LIBRARY_NAME)
$(DELETE) $(BUILD_DIR)\x86_64\*.obj
$(COPY) $(BUILD_DIR)\x86_64\*.* $(RESOURCE_DIR)\x86_64
$(DELETE) ..\*.h
$(RMDIR) $(BUILD_DIR)\..
# Rule to create build directories
checkdirs : $(BUILD_DIR)/x86 $(BUILD_DIR)/x86_64
$(BUILD_DIR)/x86 :
checkdirs : $(BUILD_DIR)\x86 $(BUILD_DIR)\x86_64
$(BUILD_DIR)\x86 :
$(MKDIR) "$@"
$(BUILD_DIR)/x86_64 :
$(BUILD_DIR)\x86_64 :
$(MKDIR) "$@"
# Rule to build 32-bit library
$(BUILD_DIR)/x86/$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86)
$(BUILD_DIR)\x86\$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86)
$(LINK) $(LDFLAGS) /MACHINE:X86 /OUT:$@ $(OBJECTSx86) $(LIBRARIES)
# Rule to build 64-bit library
$(BUILD_DIR)/x86_64/$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86_64)
$(BUILD_DIR)\x86_64\$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86_64)
$(LINK) $(LDFLAGS) /MACHINE:X64 /OUT:$@ $(OBJECTSx86_64) $(LIBRARIES)
# Suffix rules to get from *.cpp -> *.o
$(BUILD_DIR)/x86/%.o : %.cpp
$(COMPILE) $(CFLAGS) $(INCLUDES) $< -Fo$@
$(BUILD_DIR)/x86_64/%.o : %.cpp
$(COMPILE) $(CFLAGS) $(INCLUDES) $< -Fo$@
# Suffix rules to get from *.cpp -> *.obj
$(OBJECTSx86_64) : $(*B).cpp
$(COMPILE) $(CFLAGS) $(INCLUDES) $? -Fo$@
$(OBJECTSx86) : $(*B).cpp
$(COMPILE) $(CFLAGS) $(INCLUDES) $? -Fo$@
# Rule to build JNI header file
$(JNI_HEADER) : $(JAVA_CLASS)
$(JAVAH) -d .. -classpath $(JAVA_CLASS_DIR)/../../.. $(FULL_CLASS)
$(JAVAH) -d .. -classpath $(JAVA_CLASS_DIR)\..\..\.. $(FULL_CLASS)
# Suffix rule to get from *.java -> *.class
$(JAVA_CLASS) :
$(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)/../../.. $(JAVA_SOURCE_DIR)/$(basename $(notdir $@)).java
$(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)\..\..\.. -cp $(JAVA_SOURCE_DIR)\..\..\.. $(JAVA_SOURCE_DIR)\$(*B).java

View File

@ -202,7 +202,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNati
// Configure the port parameters and timeouts
if (Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj) && Java_com_fazecast_jSerialComm_SerialPort_configFlowControl(env, obj) &&
Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj))
Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj))
env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_TRUE);
else
{
@ -312,7 +312,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = readTimeout;
timeouts.WriteTotalTimeoutConstant = 10;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING): // Read/Write Semi-blocking
timeouts.ReadIntervalTimeout = MAXDWORD;
@ -330,7 +330,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = readTimeout;
timeouts.WriteTotalTimeoutConstant = 10;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING): // Read Blocking/Write Semi-blocking
timeouts.ReadIntervalTimeout = 0;
@ -349,7 +349,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutConstant = 10;
timeouts.WriteTotalTimeoutConstant = 0;
break;
}
@ -357,6 +357,78 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
return SetCommTimeouts(serialHandle, &timeouts);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(JNIEnv *env, jobject obj)
{
jclass serialCommClass = env->GetObjectClass(obj);
HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J"));
// Get event flags from Java class
int eventsToMonitor = env->GetIntField(obj, env->GetFieldID(serialCommClass, "eventFlags", "I"));
int eventFlags = 0;
if (((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) > 0) ||
((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0))
eventFlags |= EV_RXCHAR;
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN) > 0)
eventFlags |= EV_TXEMPTY;
// Change read timeouts if we are monitoring data received
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0)
{
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 1000;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(serialPortHandle, &timeouts);
}
else
Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj);
// Apply changes
return SetCommMask(serialPortHandle, eventFlags);
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj)
{
jclass serialCommClass = env->GetObjectClass(obj);
HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J"));
OVERLAPPED overlappedStruct = {0};
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL)
{
CloseHandle(overlappedStruct.hEvent);
return -1;
}
// Wait for a serial port event
DWORD eventMask, numBytesRead;
if (WaitCommEvent(serialPortHandle, &eventMask, &overlappedStruct) == FALSE)
{
if (GetLastError() != ERROR_IO_PENDING) // Problem occurred
{
// Problem reading, close port
CloseHandle(serialPortHandle);
serialPortHandle = INVALID_HANDLE_VALUE;
env->SetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J"), (jlong)INVALID_HANDLE_VALUE);
env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_FALSE);
}
else if (GetOverlappedResult(serialPortHandle, &overlappedStruct, &numBytesRead, TRUE) == FALSE)
{
// Problem reading, close port
CloseHandle(serialPortHandle);
serialPortHandle = INVALID_HANDLE_VALUE;
env->SetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J"), (jlong)INVALID_HANDLE_VALUE);
env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_FALSE);
}
}
// Return type of event if successful
CloseHandle(overlappedStruct.hEvent);
return ((eventMask & EV_RXCHAR) > 0) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE :
(((eventMask & EV_TXEMPTY) > 0) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN : 0);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative(JNIEnv *env, jobject obj)
{
// Purge any outstanding port operations

View File

@ -39,7 +39,7 @@ import java.io.OutputStream;
* @see java.io.InputStream
* @see java.io.OutputStream
*/
public class SerialPort
public final class SerialPort
{
// Static initializer loads correct native library for this machine
static
@ -145,11 +145,18 @@ public class SerialPort
static final public int TIMEOUT_READ_BLOCKING = 0x00000100;
static final public int TIMEOUT_WRITE_BLOCKING = 0x00001000;
// Serial Port Listening Events
static final public int LISTENING_EVENT_DATA_AVAILABLE = 0x00000001;
static final public int LISTENING_EVENT_DATA_RECEIVED = 0x00000010;
static final public int LISTENING_EVENT_DATA_WRITTEN = 0x00000100;
// Serial Port Parameters
private volatile int baudRate = 9600, dataBits = 8, stopBits = ONE_STOP_BIT, parity = NO_PARITY;
private volatile int baudRate = 9600, dataBits = 8, stopBits = ONE_STOP_BIT, parity = NO_PARITY, eventFlags = 0;
private volatile int timeoutMode = TIMEOUT_NONBLOCKING, readTimeout = 0, writeTimeout = 0, flowControl = 0;
private volatile SerialPortInputStream inputStream = null;
private volatile SerialPortOutputStream outputStream = null;
private volatile SerialPortDataListener userDataListener = null;
private volatile SerialPortEventListener serialEventListener = null;
private volatile String portString, comPort;
private volatile long portHandle = -1l;
private volatile boolean isOpened = false;
@ -168,6 +175,8 @@ public class SerialPort
{
inputStream = new SerialPortInputStream();
outputStream = new SerialPortOutputStream();
if (serialEventListener != null)
serialEventListener.startListening();
}
return isOpened;
}
@ -181,6 +190,8 @@ public class SerialPort
{
if (isOpened && closePortNative())
{
if (serialEventListener != null)
serialEventListener.stopListening();
inputStream = null;
outputStream = null;
}
@ -188,11 +199,13 @@ public class SerialPort
}
// Serial Port Setup Methods
private final native boolean openPortNative();
private final native boolean closePortNative();
private final native boolean configPort(); // Changes/sets serial port parameters as defined by this class
private final native boolean configFlowControl(); // Changes/sets flow control parameters as defined by this class
private final native boolean configTimeouts(); // Changes/sets serial port timeouts as defined by this class
private final native boolean openPortNative(); // Opens serial port
private final native boolean closePortNative(); // Closes serial port
private final native boolean configPort(); // Changes/sets serial port parameters as defined by this class
private final native boolean configFlowControl(); // Changes/sets flow control parameters as defined by this class
private final native boolean configTimeouts(); // Changes/sets serial port timeouts as defined by this class
private final native boolean configEventFlags(); // Changes/sets which serial events to listen for as defined by this class
private final native int waitForEvent(); // Waits for serial event to occur as specified in eventFlags
/**
* Returns the number of bytes available without blocking if {@link #readBytes} were to be called immediately
@ -235,6 +248,64 @@ public class SerialPort
// Default Constructor
public SerialPort() {}
/**
* Adds a {@link SerialPortDataListener} to the serial port interface.
* <p>
* Calling this function enables event-based serial port callbacks to be used instead of, or in addition to, direct serial port read/write calls or the {@link java.io.InputStream}/{@link java.io.OutputStream} interface.
* <p>
* The parameter passed into this method must be an implementation of either the {@link SerialPortDataListener} or the {@link SerialPortPacketListener}.
* The {@link SerialPortPacketListener} interface <b>must</b> be used if you plan to use event-based reading of <i>full</i> data packets over the serial port.
* Otherwise, the simpler {@link SerialPortDataListener} may be used.
* <p>
* Only one listener can be registered at a time; however, that listener can be used to detect multiple types of serial port events.
* Refer to {@link SerialPortDataListener} and {@link SerialPortPacketListener} for more information.
*
* @param listener A {@link SerialPortDataListener} or {@link SerialPortPacketListener}implementation to be used for event-based serial port communications.
* @return Whether the listener was successfully registered with the serial port.
* @see SerialPortDataListener
* @see SerialPortPacketListener
*/
public final boolean addDataListener(SerialPortDataListener listener)
{
if (userDataListener != null)
return false;
userDataListener = listener;
serialEventListener = new SerialPortEventListener((userDataListener instanceof SerialPortPacketListener) ?
((SerialPortPacketListener)userDataListener).getPacketSize() : 0);
eventFlags = 0;
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_AVAILABLE) > 0)
eventFlags |= LISTENING_EVENT_DATA_AVAILABLE;
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_RECEIVED) > 0)
eventFlags |= LISTENING_EVENT_DATA_RECEIVED;
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_WRITTEN) > 0)
eventFlags |= LISTENING_EVENT_DATA_WRITTEN;
if (isOpened)
{
configEventFlags();
serialEventListener.startListening();
}
return true;
}
/**
* Removes the associated {@link SerialPortDataListener} from the serial port interface.
*/
public final void removeDataListener()
{
if (serialEventListener != null)
{
serialEventListener.stopListening();
serialEventListener = null;
}
userDataListener = null;
eventFlags = 0;
if (isOpened)
configEventFlags();
}
/**
* Returns an {@link java.io.InputStream} object associated with this serial port.
* <p>
@ -288,13 +359,14 @@ public class SerialPort
*/
public final void setComPortParameters(int newBaudRate, int newDataBits, int newStopBits, int newParity)
{
baudRate = newBaudRate;
dataBits = newDataBits;
stopBits = newStopBits;
parity = newParity;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
baudRate = newBaudRate;
dataBits = newDataBits;
stopBits = newStopBits;
parity = newParity;
configPort();
}
}
@ -335,12 +407,13 @@ public class SerialPort
*/
public final void setComPortTimeouts(int newTimeoutMode, int newReadTimeout, int newWriteTimeout)
{
timeoutMode = newTimeoutMode;
readTimeout = newReadTimeout;
writeTimeout = newWriteTimeout;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
timeoutMode = newTimeoutMode;
readTimeout = newReadTimeout;
writeTimeout = newWriteTimeout;
configTimeouts();
}
}
@ -354,10 +427,11 @@ public class SerialPort
*/
public final void setBaudRate(int newBaudRate)
{
baudRate = newBaudRate;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
baudRate = newBaudRate;
configPort();
}
}
@ -371,10 +445,11 @@ public class SerialPort
*/
public final void setNumDataBits(int newDataBits)
{
dataBits = newDataBits;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
dataBits = newDataBits;
configPort();
}
}
@ -394,10 +469,11 @@ public class SerialPort
*/
public final void setNumStopBits(int newStopBits)
{
stopBits = newStopBits;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
stopBits = newStopBits;
configPort();
}
}
@ -432,10 +508,11 @@ public class SerialPort
*/
public final void setFlowControl(int newFlowControlSettings)
{
flowControl = newFlowControlSettings;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
flowControl = newFlowControlSettings;
configFlowControl();
}
}
@ -455,10 +532,11 @@ public class SerialPort
*/
public final void setParity(int newParity)
{
parity = newParity;
if (isOpened)
{
try { Thread.sleep(200); } catch (Exception e) {}
parity = newParity;
configPort();
}
}
@ -572,6 +650,84 @@ public class SerialPort
*/
public final int getFlowControlSettings() { return flowControl; }
// Private EventListener class
private final class SerialPortEventListener
{
private volatile boolean isListening = false;
private final byte[] dataPacket;
private volatile int dataPacketIndex = 0;
public SerialPortEventListener(int packetSizeToReceive) { dataPacket = new byte[packetSizeToReceive]; }
public final void startListening()
{
if (isListening)
return;
isListening = true;
new Thread(new Runnable() {
@Override
public void run()
{
while (isListening && isOpened)
waitForSerialEvent();
isListening = false;
}
}).start();
}
public final void stopListening()
{
if (!isListening)
return;
isListening = false;
}
public final void waitForSerialEvent()
{
switch (waitForEvent())
{
case LISTENING_EVENT_DATA_AVAILABLE:
{
if ((eventFlags & LISTENING_EVENT_DATA_RECEIVED) > 0)
{
// Read data from serial port
int numBytesAvailable, bytesRemaining, newBytesIndex;
while ((numBytesAvailable = bytesAvailable()) > 0)
{
byte[] newBytes = new byte[numBytesAvailable];
newBytesIndex = 0;
bytesRemaining = readBytes(newBytes, newBytes.length);
while (bytesRemaining >= (dataPacket.length - dataPacketIndex))
{
System.arraycopy(newBytes, newBytesIndex, dataPacket, dataPacketIndex, dataPacket.length - dataPacketIndex);
bytesRemaining -= (dataPacket.length - dataPacketIndex);
newBytesIndex += (dataPacket.length - dataPacketIndex);
dataPacketIndex = 0;
userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, dataPacket.clone()));
}
if (bytesRemaining > 0)
{
System.arraycopy(newBytes, newBytesIndex, dataPacket, dataPacketIndex, bytesRemaining);
dataPacketIndex += bytesRemaining;
}
}
}
else if ((eventFlags & LISTENING_EVENT_DATA_AVAILABLE) > 0)
userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_AVAILABLE));
break;
}
case LISTENING_EVENT_DATA_WRITTEN:
{
userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_WRITTEN));
break;
}
default:
break;
}
}
}
// InputStream interface class
private final class SerialPortInputStream extends InputStream
{

View File

@ -0,0 +1,13 @@
package com.fazecast.jSerialComm;
import java.util.EventListener;
public interface SerialPortDataListener extends EventListener
{
// TODO: Documentation - can OR together desired listening events
// Reading vs data available precedence
public abstract int getListeningEvents();
// TODO: Documentation
public abstract void serialEvent(SerialPortEvent event);
}

View File

@ -0,0 +1,35 @@
package com.fazecast.jSerialComm;
import java.util.EventObject;
public final class SerialPortEvent extends EventObject
{
private static final long serialVersionUID = 3060830619653354150L;
private final int eventType;
private final byte[] serialData;
public SerialPortEvent(Object source, int serialEventType)
{
super(source);
eventType = serialEventType;
serialData = null;
}
public SerialPortEvent(Object source, int serialEventType, byte[] data)
{
super(source);
eventType = serialEventType;
serialData = data;
}
public final int getEventType() { return eventType; }
public final byte[] getReceivedData() { return serialData; }
//TODO: Implementations: DataAvailableListener(void), return how much data is available
//TODO: Implementations: DataReceivedListener(Set amount of data to read before notifying)
//Should not mix DataReceivedListener with direct reads (read(), readBytes(), etc) or with InputStream usage
//Note: Using DataReceivedListener will negate any COM port read timeout settings since they make no sense in this context
//TODO: Implementations: DataWrittenListener(Return with number of bytes written)
}

View File

@ -0,0 +1,6 @@
package com.fazecast.jSerialComm;
public interface SerialPortPacketListener extends SerialPortDataListener
{
public abstract int getPacketSize();
}

View File

@ -107,7 +107,25 @@ public class SerialPortTest
System.out.println("Read " + numRead + " bytes.");
}
} catch (Exception e) { e.printStackTrace(); }
System.out.println("\nSwitching over to event-based reading");
ubxPort.addDataListener(new SerialPortPacketListener() {
@Override
public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }
@Override
public void serialEvent(SerialPortEvent event)
{
byte[] newData = event.getReceivedData();
System.out.println("Received data of size: " + newData.length);
for (int i = 0; i < newData.length; ++i)
System.out.print((char)newData[i]);
System.out.println("\n");
}
@Override
public int getPacketSize() { return 100; }
});
try { Thread.sleep(5000); } catch (Exception e) {}
System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
ubxPort.removeDataListener();
try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); }
System.out.println("Reopening " + ubxPort.getDescriptivePortName() + ": " + ubxPort.openPort() + "\n");
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);