Windows and Linux serial port support. Also played with I/O streams.
authorDoug Schaefer <dschaefer@qnx.com>
Tue, 7 Apr 2015 18:36:56 +0000 (14:36 -0400)
committerGerrit Code Review @ Eclipse.org <gerrit@eclipse.org>
Wed, 8 Apr 2015 17:29:05 +0000 (13:29 -0400)
Added buffered writes as well as non-native unbuffered reads.

Change-Id: I3577746ed8215844e02601608f4a9173d1639aa1

27 files changed:
core/org.eclipse.cdt.core.win32/library/cdt-win32.sln
core/org.eclipse.cdt.core.win32/library/serial/.gitignore [deleted file]
core/org.eclipse.cdt.core.win32/library/serial/dllmain.cpp [deleted file]
core/org.eclipse.cdt.core.win32/library/serial/serial.cpp [deleted file]
core/org.eclipse.cdt.core.win32/library/serial/stdafx.cpp [deleted file]
core/org.eclipse.cdt.core.win32/library/serial/stdafx.h [deleted file]
core/org.eclipse.cdt.core.win32/library/serial/targetver.h [deleted file]
native/org.eclipse.cdt.native.serial/jni/posix/.gitignore [moved from native/org.eclipse.cdt.native.serial/jni/.gitignore with 100% similarity]
native/org.eclipse.cdt.native.serial/jni/posix/Makefile
native/org.eclipse.cdt.native.serial/jni/posix/serial.c
native/org.eclipse.cdt.native.serial/jni/win32/serial/.gitignore [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/jni/win32/serial/dllmain.cpp [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.cpp [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.sln [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.vcxproj [moved from core/org.eclipse.cdt.core.win32/library/serial/serial.vcxproj with 91% similarity]
native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.vcxproj.filters [moved from core/org.eclipse.cdt.core.win32/library/serial/serial.vcxproj.filters with 92% similarity]
native/org.eclipse.cdt.native.serial/jni/win32/serial/stdafx.cpp [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/jni/win32/serial/stdafx.h [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/jni/win32/serial/targetver.h [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/os/linux/x86/libserial.so [new file with mode: 0755]
native/org.eclipse.cdt.native.serial/os/linux/x86_64/libserial.so [new file with mode: 0755]
native/org.eclipse.cdt.native.serial/os/macosx/x86_64/libserial.jnilib
native/org.eclipse.cdt.native.serial/os/win32/x86/.gitignore [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/os/win32/x86/serial.dll [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/os/win32/x86_64/.gitignore [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/os/win32/x86_64/serial.dll [new file with mode: 0644]
native/org.eclipse.cdt.native.serial/src/org/eclipse/cdt/serial/SerialPort.java

index da36400..5367a43 100644 (file)
@@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 2013\r
 VisualStudioVersion = 12.0.31101.0\r
 MinimumVisualStudioVersion = 10.0.40219.1\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "serial", "serial\serial.vcxproj", "{2E2DB53A-62BE-4690-8FCB-209885DD9B3C}"\r
-EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winreg", "winreg\winreg.vcxproj", "{4CA57EA3-42F2-4CC1-8E95-5C707A8E7363}"\r
 EndProject\r
 Global\r
@@ -17,18 +15,6 @@ Global
                Release|x64 = Release|x64\r
        EndGlobalSection\r
        GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Debug|Win32.Build.0 = Debug|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Debug|x64.ActiveCfg = Debug|x64\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Debug|x64.Build.0 = Debug|x64\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Release|Mixed Platforms.Build.0 = Release|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Release|Win32.ActiveCfg = Release|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Release|Win32.Build.0 = Release|Win32\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Release|x64.ActiveCfg = Release|x64\r
-               {2E2DB53A-62BE-4690-8FCB-209885DD9B3C}.Release|x64.Build.0 = Release|x64\r
                {4CA57EA3-42F2-4CC1-8E95-5C707A8E7363}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r
                {4CA57EA3-42F2-4CC1-8E95-5C707A8E7363}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r
                {4CA57EA3-42F2-4CC1-8E95-5C707A8E7363}.Debug|Win32.ActiveCfg = Debug|Win32\r
diff --git a/core/org.eclipse.cdt.core.win32/library/serial/.gitignore b/core/org.eclipse.cdt.core.win32/library/serial/.gitignore
deleted file mode 100644 (file)
index 5d72c45..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/serial.tlog/
-/serial.vcxproj.user
diff --git a/core/org.eclipse.cdt.core.win32/library/serial/dllmain.cpp b/core/org.eclipse.cdt.core.win32/library/serial/dllmain.cpp
deleted file mode 100644 (file)
index 6e29798..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2015 QNX Software Systems and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     QNX Software Systems - Initial API and implementation\r
- *******************************************************************************/\r
-#include "stdafx.h"\r
-\r
-BOOL APIENTRY DllMain( HMODULE hModule,\r
-                       DWORD  ul_reason_for_call,\r
-                       LPVOID lpReserved\r
-                                        )\r
-{\r
-       switch (ul_reason_for_call)\r
-       {\r
-       case DLL_PROCESS_ATTACH:\r
-       case DLL_THREAD_ATTACH:\r
-       case DLL_THREAD_DETACH:\r
-       case DLL_PROCESS_DETACH:\r
-               break;\r
-       }\r
-       return TRUE;\r
-}\r
-\r
diff --git a/core/org.eclipse.cdt.core.win32/library/serial/serial.cpp b/core/org.eclipse.cdt.core.win32/library/serial/serial.cpp
deleted file mode 100644 (file)
index 69a1de3..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2015 QNX Software Systems and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     QNX Software Systems - Initial API and implementation\r
- *******************************************************************************/\r
-#include "stdafx.h"\r
-\r
-extern "C"\r
-JNIEXPORT jlong JNICALL Java_org_eclipse_cdt_utils_serial_SerialPort_open0\r
-(JNIEnv *env, jobject jobj, jstring portName, jint baudRate, jint byteSize, jint parity, jint stopBits)\r
-{\r
-       const wchar_t * cportName = (const wchar_t *) env->GetStringChars(portName, NULL);\r
-       HANDLE handle = CreateFile(cportName,\r
-               GENERIC_READ | GENERIC_WRITE,\r
-               0,\r
-               NULL,\r
-               OPEN_EXISTING,\r
-               FILE_FLAG_OVERLAPPED,\r
-               NULL);\r
-\r
-       if (handle != INVALID_HANDLE_VALUE) {\r
-               DCB dcb = { 0 };\r
-\r
-               if (!GetCommState(handle, &dcb)) {\r
-                       fprintf(stderr, "Error getting DCB: %S\n", cportName);\r
-                       return -1;\r
-               }\r
-\r
-               dcb.BaudRate = baudRate;\r
-               dcb.ByteSize = (BYTE) byteSize;\r
-\r
-               switch (parity) {\r
-               case 0: // None\r
-                       dcb.fParity = FALSE;\r
-                       break;\r
-               case 1: // Even\r
-                       dcb.fParity = TRUE;\r
-                       dcb.Parity = EVENPARITY;\r
-                       break;\r
-               case 2: // Odd\r
-                       dcb.fParity = TRUE;\r
-                       dcb.Parity = ODDPARITY;\r
-                       break;\r
-               }\r
-               \r
-               switch (stopBits) {\r
-               case 0:\r
-                       dcb.StopBits = ONESTOPBIT;\r
-                       break;\r
-               case 1:\r
-                       dcb.StopBits = TWOSTOPBITS;\r
-                       break;\r
-               }\r
-\r
-               if (!SetCommState(handle, &dcb)) {\r
-                       fprintf(stderr, "Error setting DCB: %S\n", cportName);\r
-                       return -1;\r
-               }\r
-       }\r
-\r
-       return (jlong) handle;\r
-}\r
-\r
-extern "C"\r
-JNIEXPORT void JNICALL Java_org_eclipse_cdt_utils_serial_SerialPort_close0\r
-(JNIEnv *env, jobject jobj, jlong handle)\r
-{\r
-       CloseHandle((HANDLE) handle);\r
-}\r
-\r
-extern "C"\r
-JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_serial_SerialPort_read0\r
-(JNIEnv *env, jobject jobj, jlong jhandle)\r
-{\r
-       OVERLAPPED olp = { 0 };\r
-\r
-       olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
-       if (olp.hEvent == NULL) {\r
-               fprintf(stderr, "Error creating event\n");\r
-               fflush(stderr);\r
-               return -1;\r
-       }\r
-\r
-       char buff;\r
-       DWORD nwritten;\r
-       HANDLE handle = (HANDLE)jhandle;\r
-\r
-       if (!ReadFile(handle, &buff, sizeof(buff), &nwritten, &olp)) {\r
-               if (GetLastError() != ERROR_IO_PENDING) {\r
-                       fprintf(stderr, "Error reading from port: %d\n", GetLastError());\r
-                       fflush(stderr);\r
-                       return -1;\r
-               }\r
-               else {\r
-                       switch (WaitForSingleObject(olp.hEvent, INFINITE)) {\r
-                       case WAIT_OBJECT_0:\r
-                               if (!GetOverlappedResult(handle, &olp, &nwritten, FALSE)) {\r
-                                       if (GetLastError() != ERROR_OPERATION_ABORTED) {\r
-                                               fprintf(stderr, "Error waiting for read: %d\n", GetLastError());\r
-                                               fflush(stderr);\r
-                                       }\r
-                                       return -1;\r
-                               }\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       CloseHandle(olp.hEvent);\r
-       return buff;\r
-}\r
-\r
-extern "C"\r
-JNIEXPORT void JNICALL Java_org_eclipse_cdt_utils_serial_SerialPort_write0\r
-(JNIEnv *env, jobject jobj, jlong jhandle, jint b)\r
-{\r
-       OVERLAPPED olp = { 0 };\r
-\r
-       olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
-       if (olp.hEvent == NULL) {\r
-               fprintf(stderr, "Error creating event\n");\r
-               return;\r
-       }\r
-\r
-       char buff = (char) b;\r
-       DWORD nwritten;\r
-       HANDLE handle = (HANDLE) jhandle;\r
-\r
-       if (!WriteFile(handle, &buff, sizeof(buff), &nwritten, &olp)) {\r
-               if (GetLastError() != ERROR_IO_PENDING) {\r
-                       fprintf(stderr, "Error writing to port\n");\r
-               }\r
-               else {\r
-                       switch (WaitForSingleObject(olp.hEvent, INFINITE)) {\r
-                       case WAIT_OBJECT_0:\r
-                               if (!GetOverlappedResult(handle, &olp, &nwritten, FALSE)) {\r
-                                       fprintf(stderr, "Error waiting for write\n");\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       CloseHandle(olp.hEvent);\r
-}\r
diff --git a/core/org.eclipse.cdt.core.win32/library/serial/stdafx.cpp b/core/org.eclipse.cdt.core.win32/library/serial/stdafx.cpp
deleted file mode 100644 (file)
index c97de4c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2015 QNX Software Systems and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     QNX Software Systems - Initial API and implementation\r
- *******************************************************************************/\r
-#include "stdafx.h"\r
-\r
-// TODO: reference any additional headers you need in STDAFX.H\r
-// and not in this file\r
diff --git a/core/org.eclipse.cdt.core.win32/library/serial/stdafx.h b/core/org.eclipse.cdt.core.win32/library/serial/stdafx.h
deleted file mode 100644 (file)
index 0babced..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2015 QNX Software Systems and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     QNX Software Systems - Initial API and implementation\r
- *******************************************************************************/\r
-#pragma once\r
-\r
-#include "targetver.h"\r
-\r
-#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\r
-// Windows Header Files:\r
-#include <windows.h>\r
-#include <jni.h>\r
-\r
-\r
-\r
-// TODO: reference additional headers your program requires here\r
diff --git a/core/org.eclipse.cdt.core.win32/library/serial/targetver.h b/core/org.eclipse.cdt.core.win32/library/serial/targetver.h
deleted file mode 100644 (file)
index d27181a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2015 QNX Software Systems and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     QNX Software Systems - Initial API and implementation\r
- *******************************************************************************/\r
-#pragma once\r
-\r
-// Including SDKDDKVer.h defines the highest available Windows platform.\r
-\r
-// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\r
-// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\r
-\r
-#include <SDKDDKVer.h>\r
index 9952967..8dbea9a 100644 (file)
 #     Alex Blewitt - MacOSX with a 64-bit vm 
 #*******************************************************************************/
 
-JAVA_HOME = $(shell echo /Library/Java/JavaVirtualMachines/jdk1.8.0_*.jdk/Contents/Home)
 UNAME = $(shell uname)
 
 # Defaults which can be overridden.
 ifeq ($(UNAME),Darwin)
+JAVA_HOME = $(shell echo /Library/Java/JavaVirtualMachines/jdk1.8.0_*.jdk/Contents/Home)
 OS = macosx
+JNI_OS = darwin
 ARCHS = x86_64
+ARCH_FLAG_X86 = -arch i386
+ARCH_FLAG_X86_64 = -arch x86_64
+LDFLAGS = -dynamiclib
+LIBEXT = jnilib
+else
+ifeq ($(UNAME),Linux)
+JAVA_HOME = /usr/lib/jvm/java-8-oracle
+OS = linux
+JNI_OS = linux
+ARCHS = x86 x86_64
+ARCH_FLAG_X86 = -m32
+ARCH_FLAG_X86_64 = -m64
+LDFLAGS = -shared
+LIBEXT = so
+endif
 endif
 
 ARCH_X86 = x86
@@ -24,17 +40,14 @@ ARCH_X86_64 = x86_64
 
 CC=gcc
 LD=libtool
-CPPFLAGS = -I. -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin
+CPPFLAGS = -I. -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/$(JNI_OS)
 CFLAGS +=-fPIC -D_REENTRANT
 
-ARCH_FLAG_X86 = -arch i386
-ARCH_FLAG_X86_64 = -arch x86_64
-
 INSTALL_DIR_X86 = ../../os/$(OS)/$(ARCH_X86)
 INSTALL_DIR_X86_64 = ../../os/$(OS)/$(ARCH_X86_64)
 
-LIB_NAME_FULL_SERIAL_X86 = $(INSTALL_DIR_X86)/libserial.jnilib
-LIB_NAME_FULL_SERIAL_X86_64 = $(INSTALL_DIR_X86_64)/libserial.jnilib
+LIB_NAME_FULL_SERIAL_X86 = $(INSTALL_DIR_X86)/libserial.$(LIBEXT)
+LIB_NAME_FULL_SERIAL_X86_64 = $(INSTALL_DIR_X86_64)/libserial.$(LIBEXT)
 
 OBJS_SERIAL_X86 = serial_$(ARCH_X86).o
 OBJS_SERIAL_X86_64 = serial_$(ARCH_X86_64).o
@@ -52,11 +65,11 @@ rebuild: clean all
 
 $(LIB_NAME_FULL_SERIAL_X86): $(OBJS_SERIAL_X86)
        mkdir -p $(INSTALL_DIR_X86)
-       $(CC) -dynamiclib  $(ARCH_FLAG_X86) -o $(LIB_NAME_FULL_SERIAL_X86) $(OBJS_SERIAL_X86) -lc -framework JavaVM
+       $(CC) $(LDFLAGS)  $(ARCH_FLAG_X86) -o $(LIB_NAME_FULL_SERIAL_X86) $(OBJS_SERIAL_X86)
 
 $(LIB_NAME_FULL_SERIAL_X86_64): $(OBJS_SERIAL_X86_64)
        mkdir -p $(INSTALL_DIR_X86_64)
-       $(CC) -dynamiclib  $(ARCH_FLAG_X86_64) -o $(LIB_NAME_FULL_SERIAL_X86_64) $(OBJS_SERIAL_X86_64) -lc -framework JavaVM
+       $(CC) $(LDFLAGS)  $(ARCH_FLAG_X86_64) -o $(LIB_NAME_FULL_SERIAL_X86_64) $(OBJS_SERIAL_X86_64)
 
 serial_$(ARCH_X86).o: serial.c
        $(CC) $(CFLAGS) $(ARCH_FLAG_X86) $(CPPFLAGS) -c -o $@ serial.c
index bf1e51d..3bc71e4 100644 (file)
@@ -8,9 +8,11 @@
  * Contributors:
  *     QNX Software Systems - initial API and implementation
  *******************************************************************************/
+#ifdef __APPLE__
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/uio.h>
+#endif
 #include <unistd.h>
 #include <fcntl.h>
 #include <termios.h>
@@ -26,6 +28,7 @@ JNIEXPORT jlong JNICALL FUNC(open0)(JNIEnv *env, jobject jobj, jstring portName,
        const char * cportName = (*env)->GetStringUTFChars(env, portName, NULL);
        int fd = open(cportName, O_RDWR | O_NOCTTY | O_NDELAY);
        if (fd < 0) {
+               perror(cportName);
                return fd;
        }
 
@@ -88,7 +91,7 @@ JNIEXPORT jlong JNICALL FUNC(open0)(JNIEnv *env, jobject jobj, jstring portName,
        options.c_iflag |= IGNPAR;
 
        options.c_cc[VMIN]     = 0;   // min chars to read
-       options.c_cc[VTIME]    = 10;   // 10ths second timeout
+       options.c_cc[VTIME]    = 2;   // 10ths second timeout
 
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd, TCSANOW, &options);
@@ -97,18 +100,12 @@ JNIEXPORT jlong JNICALL FUNC(open0)(JNIEnv *env, jobject jobj, jstring portName,
 }
 
 JNIEXPORT void JNICALL FUNC(close0)(JNIEnv *env, jobject jobj, jlong handle)
-               {
+{
        close(handle);
-               }
-
-JNIEXPORT jint JNICALL FUNC(read0)(JNIEnv *env, jobject jobj, jlong handle)
-               {
-       char buff;
-       int res = read(handle, &buff, 1);
-       return res < 0 ? -1 : buff;
-               }
+}
 
-JNIEXPORT jint JNICALL FUNC(read1)(JNIEnv * env, jobject jobj, jlong handle, jbyteArray bytes, jint offset, jint size) {
+JNIEXPORT jint JNICALL FUNC(read1)(JNIEnv * env, jobject jobj, jlong handle, jbyteArray bytes, jint offset, jint size)
+{
        jbyte buff[256];
        int n = size < sizeof(buff) ? size : sizeof(buff);
        n = read(handle, buff, n);
@@ -119,7 +116,22 @@ JNIEXPORT jint JNICALL FUNC(read1)(JNIEnv * env, jobject jobj, jlong handle, jby
 }
 
 JNIEXPORT void JNICALL FUNC(write0)(JNIEnv *env, jobject jobj, jlong handle, jint b)
-               {
+{
        char buff = b;
        write(handle, &buff, 1);
+}
+
+JNIEXPORT void JNICALL FUNC(write1)(JNIEnv *env, jobject jobj, jlong handle, jbyteArray bytes, jint offset, jint size)
+{
+       while (size > 0) {
+               jbyte buff[256];
+               int n = size < sizeof(buff) ? size : sizeof(buff);
+               (*env)->GetByteArrayRegion(env, bytes, offset, n, buff);
+               n = write(handle, buff, n);
+               if (n < 0) {
+                       return;
                }
+               size -= n;
+               offset += n;
+       }
+}
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/.gitignore b/native/org.eclipse.cdt.native.serial/jni/win32/serial/.gitignore
new file mode 100644 (file)
index 0000000..8f10bd0
--- /dev/null
@@ -0,0 +1,6 @@
+/ipch/
+/Release/
+/x64/
+/serial.opensdf
+/serial.sdf
+/serial.v12.suo
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/dllmain.cpp b/native/org.eclipse.cdt.native.serial/jni/win32/serial/dllmain.cpp
new file mode 100644 (file)
index 0000000..8a4edd3
--- /dev/null
@@ -0,0 +1,19 @@
+// dllmain.cpp : Defines the entry point for the DLL application.\r
+#include "stdafx.h"\r
+\r
+BOOL APIENTRY DllMain( HMODULE hModule,\r
+                       DWORD  ul_reason_for_call,\r
+                       LPVOID lpReserved\r
+                                        )\r
+{\r
+       switch (ul_reason_for_call)\r
+       {\r
+       case DLL_PROCESS_ATTACH:\r
+       case DLL_THREAD_ATTACH:\r
+       case DLL_THREAD_DETACH:\r
+       case DLL_PROCESS_DETACH:\r
+               break;\r
+       }\r
+       return TRUE;\r
+}\r
+\r
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.cpp b/native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.cpp
new file mode 100644 (file)
index 0000000..6bbc8c4
--- /dev/null
@@ -0,0 +1,242 @@
+/*******************************************************************************\r
+* Copyright (c) 2015 QNX Software Systems and others.\r
+* All rights reserved. This program and the accompanying materials\r
+* are made available under the terms of the Eclipse Public License v1.0\r
+* which accompanies this distribution, and is available at\r
+* http://www.eclipse.org/legal/epl-v10.html\r
+*\r
+* Contributors:\r
+*     QNX Software Systems - Initial API and implementation\r
+*******************************************************************************/\r
+#include "stdafx.h"\r
+\r
+#define FUNC(x) Java_org_eclipse_cdt_serial_SerialPort_ ## x\r
+\r
+static void throwIOException(JNIEnv *env, char *msg) {\r
+       char buff[256];\r
+       sprintf_s(buff, sizeof(buff), "%s: %d", msg, GetLastError());\r
+       jclass cls = env->FindClass("java/io/IOException");\r
+       env->ThrowNew(cls, buff);\r
+}\r
+\r
+extern "C"\r
+JNIEXPORT jlong JNICALL FUNC(open0)(JNIEnv *env, jobject jobj, jstring portName, jint baudRate, jint byteSize, jint parity, jint stopBits)\r
+{\r
+       const wchar_t * cportName = (const wchar_t *)env->GetStringChars(portName, NULL);\r
+       HANDLE handle = CreateFile(cportName,\r
+               GENERIC_READ | GENERIC_WRITE,\r
+               0,\r
+               NULL,\r
+               OPEN_EXISTING,\r
+               FILE_FLAG_OVERLAPPED,\r
+               NULL);\r
+\r
+       if (handle == INVALID_HANDLE_VALUE) {\r
+               throwIOException(env, "Error opening serial port");\r
+               return -1;\r
+       }\r
+       \r
+       DCB dcb = { 0 };\r
+\r
+       if (!GetCommState(handle, &dcb)) {\r
+               throwIOException(env, "Error getting DCB");\r
+               return -1;\r
+       }\r
+\r
+       dcb.BaudRate = baudRate;\r
+       dcb.ByteSize = (BYTE)byteSize;\r
+\r
+       switch (parity) {\r
+       case 0: // None\r
+               dcb.fParity = FALSE;\r
+               break;\r
+       case 1: // Even\r
+               dcb.fParity = TRUE;\r
+               dcb.Parity = EVENPARITY;\r
+               break;\r
+       case 2: // Odd\r
+               dcb.fParity = TRUE;\r
+               dcb.Parity = ODDPARITY;\r
+               break;\r
+       }\r
+\r
+       switch (stopBits) {\r
+       case 0:\r
+               dcb.StopBits = ONESTOPBIT;\r
+               break;\r
+       case 1:\r
+               dcb.StopBits = TWOSTOPBITS;\r
+               break;\r
+       }\r
+\r
+       if (!SetCommState(handle, &dcb)) {\r
+               throwIOException(env, "Error setting DCB");\r
+               return -1;\r
+       }\r
+\r
+       COMMTIMEOUTS timeouts = { 0 };\r
+       timeouts.ReadIntervalTimeout = MAXDWORD;\r
+       timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;\r
+       timeouts.ReadTotalTimeoutConstant = 200;\r
+       if (!SetCommTimeouts(handle, &timeouts)) {\r
+               throwIOException(env, "Error setting timeouts");\r
+               return -1;\r
+       }\r
+\r
+       return (jlong)handle;\r
+}\r
+\r
+extern "C"\r
+JNIEXPORT void JNICALL FUNC(close0)(JNIEnv *env, jobject jobj, jlong handle)\r
+{\r
+       CloseHandle((HANDLE)handle);\r
+}\r
+\r
+extern "C"\r
+JNIEXPORT jint JNICALL FUNC(read1)(JNIEnv * env, jobject jobj, jlong jhandle, jbyteArray bytes, jint offset, jint size)\r
+{\r
+       OVERLAPPED olp = { 0 };\r
+\r
+       olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+       if (olp.hEvent == NULL) {\r
+               throwIOException(env, "Error creating event");\r
+               return -1;\r
+       }\r
+\r
+       char buff[256];\r
+       DWORD nread = sizeof(buff) < size ? sizeof(buff) : size;\r
+       HANDLE handle = (HANDLE)jhandle;\r
+\r
+       if (!ReadFile(handle, buff, sizeof(buff), &nread, &olp)) {\r
+               if (GetLastError() != ERROR_IO_PENDING) {\r
+                       throwIOException(env, "Error reading from port");\r
+                       CloseHandle(olp.hEvent);\r
+                       return -1;\r
+               }\r
+               else {\r
+                       switch (WaitForSingleObject(olp.hEvent, INFINITE)) {\r
+                       case WAIT_OBJECT_0:\r
+                               if (!GetOverlappedResult(handle, &olp, &nread, FALSE)) {\r
+                                       if (GetLastError() != ERROR_OPERATION_ABORTED) {\r
+                                               throwIOException(env, "Error waiting for read");\r
+                                       }\r
+                                       CloseHandle(olp.hEvent);\r
+                                       return -1;\r
+                               }\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (nread > 0) {\r
+               env->SetByteArrayRegion(bytes, offset, nread, (jbyte *)buff);\r
+       }\r
+       CloseHandle(olp.hEvent);\r
+       return nread;\r
+}\r
+\r
+extern "C"\r
+JNIEXPORT void JNICALL FUNC(write0)(JNIEnv *env, jobject jobj, jlong jhandle, jint b)\r
+{\r
+       OVERLAPPED olp = { 0 };\r
+\r
+       olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+       if (olp.hEvent == NULL) {\r
+               throwIOException(env, "Error creating event");\r
+               return;\r
+       }\r
+\r
+       char buff = (char)b;\r
+       DWORD nwritten;\r
+       HANDLE handle = (HANDLE)jhandle;\r
+\r
+       if (!WriteFile(handle, &buff, sizeof(buff), &nwritten, &olp)) {\r
+               if (GetLastError() != ERROR_IO_PENDING) {\r
+                       throwIOException(env, "Error writing to port");\r
+               }\r
+               else {\r
+                       switch (WaitForSingleObject(olp.hEvent, INFINITE)) {\r
+                       case WAIT_OBJECT_0:\r
+                               if (!GetOverlappedResult(handle, &olp, &nwritten, FALSE)) {\r
+                                       throwIOException(env, "Error waiting for write");\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       CloseHandle(olp.hEvent);\r
+}\r
+\r
+extern "C"\r
+JNIEXPORT void JNICALL FUNC(write1)(JNIEnv *env, jobject jobj, jlong jhandle, jbyteArray bytes, jint offset, jint size)\r
+{\r
+       OVERLAPPED olp = { 0 };\r
+\r
+       olp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+       if (olp.hEvent == NULL) {\r
+               throwIOException(env, "Error creating event");\r
+               return;\r
+       }\r
+\r
+       while (size > 0) {\r
+               char buff[256];\r
+               DWORD nwritten = sizeof(buff) < size ? sizeof(buff) : size;\r
+               env->GetByteArrayRegion(bytes, offset, nwritten, (jbyte *)buff);\r
+               HANDLE handle = (HANDLE)jhandle;\r
+\r
+               if (!WriteFile(handle, buff, nwritten, &nwritten, &olp)) {\r
+                       if (GetLastError() != ERROR_IO_PENDING) {\r
+                               throwIOException(env, "Error writing to port");\r
+                               return;\r
+                       }\r
+                       else {\r
+                               switch (WaitForSingleObject(olp.hEvent, INFINITE)) {\r
+                               case WAIT_OBJECT_0:\r
+                                       if (!GetOverlappedResult(handle, &olp, &nwritten, FALSE)) {\r
+                                               throwIOException(env, "Error waiting for write");\r
+                                               return;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               size -= nwritten;\r
+               offset += nwritten;\r
+       }\r
+\r
+       CloseHandle(olp.hEvent);\r
+}\r
+\r
+extern "C"\r
+JNIEXPORT jstring FUNC(getPortName)(JNIEnv *env, jclass cls, jint i)\r
+{\r
+       HKEY key;\r
+\r
+       if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &key) != ERROR_SUCCESS) {\r
+               throwIOException(env, "Can not find registry key");\r
+               return NULL;\r
+       }\r
+\r
+       wchar_t name[256];\r
+       DWORD len = sizeof(name);\r
+       LONG rc = RegEnumValue(key, (DWORD)i, name, &len, NULL, NULL, NULL, NULL);\r
+       if (rc != ERROR_SUCCESS) {\r
+               if (rc != ERROR_NO_MORE_ITEMS) {\r
+                       throwIOException(env, "Can not enum value");\r
+               }\r
+               RegCloseKey(key);\r
+               return NULL;\r
+       }\r
+\r
+       wchar_t value[256];\r
+       DWORD type;\r
+       len = sizeof(value);\r
+       if (RegQueryValueEx(key, name, NULL, &type, (BYTE *)value, &len) != ERROR_SUCCESS) {\r
+               throwIOException(env, "Can not query value");\r
+               RegCloseKey(key);\r
+               return NULL;\r
+       }\r
+\r
+       jstring result = env->NewString((jchar *)value, (jsize) wcslen(value));\r
+       RegCloseKey(key);\r
+       return result;\r
+}\r
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.sln b/native/org.eclipse.cdt.native.serial/jni/win32/serial/serial.sln
new file mode 100644 (file)
index 0000000..0a828bd
--- /dev/null
@@ -0,0 +1,28 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 2013\r
+VisualStudioVersion = 12.0.31101.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "serial", "serial.vcxproj", "{48ED88D3-77CF-4E77-9554-10719E633142}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Debug|x64 = Debug|x64\r
+               Release|Win32 = Release|Win32\r
+               Release|x64 = Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Debug|Win32.Build.0 = Debug|Win32\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Debug|x64.ActiveCfg = Debug|x64\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Debug|x64.Build.0 = Debug|x64\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Release|Win32.ActiveCfg = Release|Win32\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Release|Win32.Build.0 = Release|Win32\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Release|x64.ActiveCfg = Release|x64\r
+               {48ED88D3-77CF-4E77-9554-10719E633142}.Release|x64.Build.0 = Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
@@ -19,7 +19,7 @@
     </ProjectConfiguration>\r
   </ItemGroup>\r
   <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{2E2DB53A-62BE-4690-8FCB-209885DD9B3C}</ProjectGuid>\r
+    <ProjectGuid>{48ED88D3-77CF-4E77-9554-10719E633142}</ProjectGuid>\r
     <Keyword>Win32Proj</Keyword>\r
     <RootNamespace>serial</RootNamespace>\r
   </PropertyGroup>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
     <LinkIncremental>false</LinkIncremental>\r
-    <OutDir>$(SolutionDir)..\..\org.eclipse.cdt.core.win32.x86\os\win32\x86\</OutDir>\r
-    <IntDir />\r
+    <OutDir>$(SolutionDir)..\..\..\os\win32\x86\</OutDir>\r
   </PropertyGroup>\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
     <LinkIncremental>false</LinkIncremental>\r
-    <OutDir>$(SolutionDir)..\..\org.eclipse.cdt.core.win32.x86_64\os\win32\x86_64\</OutDir>\r
-    <IntDir />\r
+    <OutDir>$(SolutionDir)..\..\..\os\win32\x86_64\</OutDir>\r
   </PropertyGroup>\r
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
     <ClCompile>\r
@@ -88,8 +86,6 @@
       <WarningLevel>Level3</WarningLevel>\r
       <Optimization>Disabled</Optimization>\r
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SERIAL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <SDLCheck>true</SDLCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Windows</SubSystem>\r
       <WarningLevel>Level3</WarningLevel>\r
       <Optimization>Disabled</Optimization>\r
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SERIAL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <SDLCheck>true</SDLCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Windows</SubSystem>\r
       <FunctionLevelLinking>true</FunctionLevelLinking>\r
       <IntrinsicFunctions>true</IntrinsicFunctions>\r
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SERIAL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <SDLCheck>true</SDLCheck>\r
-      <AdditionalIncludeDirectories>C:\Program Files\Java\jdk1.8.0_31\include;C:\Program Files\Java\jdk1.8.0_31\include\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalIncludeDirectories>C:\Program Files\Java\jdk1.8.0_31\include\win32;C:\Program Files\Java\jdk1.8.0_31\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
     </ClCompile>\r
     <Link>\r
       <FunctionLevelLinking>true</FunctionLevelLinking>\r
       <IntrinsicFunctions>true</IntrinsicFunctions>\r
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SERIAL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <AdditionalIncludeDirectories>C:\Program Files\Java\jdk1.8.0_31\include;C:\Program Files\Java\jdk1.8.0_31\include\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalIncludeDirectories>C:\Program Files\Java\jdk1.8.0_31\include\win32;C:\Program Files\Java\jdk1.8.0_31\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
     </ClCompile>\r
     <Link>\r
     </Link>\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
+    <Text Include="ReadMe.txt" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
     <ClInclude Include="stdafx.h" />\r
     <ClInclude Include="targetver.h" />\r
   </ItemGroup>\r
@@ -15,6 +15,9 @@
     </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Text Include="ReadMe.txt" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
     <ClInclude Include="stdafx.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/stdafx.cpp b/native/org.eclipse.cdt.native.serial/jni/win32/serial/stdafx.cpp
new file mode 100644 (file)
index 0000000..4a32c69
--- /dev/null
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes\r
+// serial.pch will be the pre-compiled header\r
+// stdafx.obj will contain the pre-compiled type information\r
+\r
+#include "stdafx.h"\r
+\r
+// TODO: reference any additional headers you need in STDAFX.H\r
+// and not in this file\r
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/stdafx.h b/native/org.eclipse.cdt.native.serial/jni/win32/serial/stdafx.h
new file mode 100644 (file)
index 0000000..935ddb4
--- /dev/null
@@ -0,0 +1,17 @@
+// stdafx.h : include file for standard system include files,\r
+// or project specific include files that are used frequently, but\r
+// are changed infrequently\r
+//\r
+\r
+#pragma once\r
+\r
+#include "targetver.h"\r
+\r
+#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\r
+// Windows Header Files:\r
+#include <windows.h>\r
+\r
+\r
+\r
+// TODO: reference additional headers your program requires here\r
+#include <jni.h>\r
diff --git a/native/org.eclipse.cdt.native.serial/jni/win32/serial/targetver.h b/native/org.eclipse.cdt.native.serial/jni/win32/serial/targetver.h
new file mode 100644 (file)
index 0000000..90e767b
--- /dev/null
@@ -0,0 +1,8 @@
+#pragma once\r
+\r
+// Including SDKDDKVer.h defines the highest available Windows platform.\r
+\r
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\r
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\r
+\r
+#include <SDKDDKVer.h>\r
diff --git a/native/org.eclipse.cdt.native.serial/os/linux/x86/libserial.so b/native/org.eclipse.cdt.native.serial/os/linux/x86/libserial.so
new file mode 100755 (executable)
index 0000000..a42fdfb
Binary files /dev/null and b/native/org.eclipse.cdt.native.serial/os/linux/x86/libserial.so differ
diff --git a/native/org.eclipse.cdt.native.serial/os/linux/x86_64/libserial.so b/native/org.eclipse.cdt.native.serial/os/linux/x86_64/libserial.so
new file mode 100755 (executable)
index 0000000..cd5e345
Binary files /dev/null and b/native/org.eclipse.cdt.native.serial/os/linux/x86_64/libserial.so differ
index bf96f91..a8eefee 100755 (executable)
Binary files a/native/org.eclipse.cdt.native.serial/os/macosx/x86_64/libserial.jnilib and b/native/org.eclipse.cdt.native.serial/os/macosx/x86_64/libserial.jnilib differ
diff --git a/native/org.eclipse.cdt.native.serial/os/win32/x86/.gitignore b/native/org.eclipse.cdt.native.serial/os/win32/x86/.gitignore
new file mode 100644 (file)
index 0000000..141e13b
--- /dev/null
@@ -0,0 +1,3 @@
+/serial.exp
+/serial.lib
+/serial.pdb
diff --git a/native/org.eclipse.cdt.native.serial/os/win32/x86/serial.dll b/native/org.eclipse.cdt.native.serial/os/win32/x86/serial.dll
new file mode 100644 (file)
index 0000000..3ac1554
Binary files /dev/null and b/native/org.eclipse.cdt.native.serial/os/win32/x86/serial.dll differ
diff --git a/native/org.eclipse.cdt.native.serial/os/win32/x86_64/.gitignore b/native/org.eclipse.cdt.native.serial/os/win32/x86_64/.gitignore
new file mode 100644 (file)
index 0000000..141e13b
--- /dev/null
@@ -0,0 +1,3 @@
+/serial.exp
+/serial.lib
+/serial.pdb
diff --git a/native/org.eclipse.cdt.native.serial/os/win32/x86_64/serial.dll b/native/org.eclipse.cdt.native.serial/os/win32/x86_64/serial.dll
new file mode 100644 (file)
index 0000000..331384f
Binary files /dev/null and b/native/org.eclipse.cdt.native.serial/os/win32/x86_64/serial.dll differ
index 62c7a9b..fc0f9f2 100644 (file)
@@ -15,6 +15,8 @@ import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.regex.Pattern;
 
 import org.eclipse.cdt.serial.internal.Messages;
@@ -32,7 +34,6 @@ public class SerialPort {
        private StopBits stopBits = StopBits.S1;
        private long handle;
 
-       private static final String SERIAL_KEY = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; //$NON-NLS-1$
        private static final String PORT_OPEN = Messages.getString("SerialPort.PortIsOpen"); //$NON-NLS-1$
 
        static {
@@ -44,10 +45,24 @@ public class SerialPort {
        }
 
        private InputStream inputStream = new InputStream() {
+               private byte[] rbuff = new byte[256];
+               private int rpos = 0;
+               private int rlen = 0;
+               
                @Override
                public int read() throws IOException {
                        if (isOpen()) {
-                               return read0(handle);
+                               if (rpos >= rlen) {
+                                       while (true) {
+                                               rlen = read1(handle, rbuff, 0, rbuff.length);
+                                               if (rlen < 0) {
+                                                       return -1;
+                                               } else if (rlen > 0) {
+                                                       break;
+                                               }
+                                       }
+                               }
+                               return rbuff[rpos++];
                        } else {
                                return -1;
                        }
@@ -56,7 +71,17 @@ public class SerialPort {
                @Override
                public int read(byte[] b, int off, int len) throws IOException {
                        if (isOpen()) {
-                               return read1(handle, b, off, len);
+                               int n = rlen - rpos;
+                               if (n > 0) {
+                                       if (len < n) {
+                                               n = len;
+                                       }
+                                       System.arraycopy(rbuff, rpos, b, off, n);
+                                       rpos += n;
+                                       return n;
+                               } else { 
+                                       return read1(handle, b, off, len);
+                               }
                        } else {
                                return -1;
                        }
@@ -77,6 +102,13 @@ public class SerialPort {
                }
 
                @Override
+               public void write(byte[] buff, int off, int len) throws IOException {
+                       if (isOpen()) {
+                               write1(handle, buff, off, len);
+                       }
+               }
+
+               @Override
                public void close() throws IOException {
                        SerialPort.this.close();
                }
@@ -91,62 +123,61 @@ public class SerialPort {
                this.portName = portName;
        }
 
+       private native long open0(String portName, int baudRate, int byteSize, int parity, int stopBits) throws IOException;
+
+       private native void close0(long handle) throws IOException;
+
+       private native int read1(long handle, byte[] b, int off, int len) throws IOException;
+
+       private native void write0(long handle, int b) throws IOException;
+       
+       private native void write1(long handle, byte[] b, int off, int len) throws IOException;
+       
+       private static native String getPortName(int i) throws IOException;
+
+       private static String[] listDevs(final Pattern pattern) {
+               File dev = new File("/dev"); //$NON-NLS-1$
+               File[] files = dev.listFiles(new FilenameFilter() {
+                       @Override
+                       public boolean accept(File dir, String name) {
+                               return pattern.matcher(name).matches();
+                       }
+               });
+               
+               if (files == null) {
+                       return new String[0];
+               }
+
+               String[] names = new String[files.length];
+               for (int i = 0; i < files.length; i++) {
+                       names[i] = files[i].getAbsolutePath();
+               }
+               return names;
+       }
+
        /**
         * List the available serial ports.
         * 
         * @return serial ports
         */
-       public static String[] list() {
-               if (System.getProperty("os.name").equals("Mac OS X")) {  //$NON-NLS-1$//$NON-NLS-2$
-                       File dev = new File("/dev"); //$NON-NLS-1$
-                       final Pattern pattern = Pattern.compile("tty\\.(usbserial|usbmodem).*"); //$NON-NLS-1$
-                       File[] files = dev.listFiles(new FilenameFilter() {
-                               @Override
-                               public boolean accept(File dir, String name) {
-                                       return pattern.matcher(name).matches();
-                               }
-                       });
-                       
-                       if (files == null) {
-                               return new String[0];
+       public static String[] list() throws IOException {
+               String osName = System.getProperty("os.name"); //$NON-NLS-1$
+               if (osName.equals("Mac OS X")) { //$NON-NLS-1$
+                       return listDevs(Pattern.compile("tty\\.(usbserial|usbmodem).*")); //$NON-NLS-1$
+               } else if (osName.equals("Linux")) { //$NON-NLS-1$
+                       return listDevs(Pattern.compile("ttyUSB.*")); //$NON-NLS-1$
+               } else if (osName.startsWith("Windows")) {  //$NON-NLS-1$
+                       List<String> ports = new ArrayList<>();
+                       int i = 0;
+                       for (String name = getPortName(i++); name != null; name = getPortName(i++)) {
+                               ports.add(name);
                        }
-                       String[] names = new String[files.length];
-                       for (int i = 0; i < files.length; i++) {
-                               names[i] = files[i].getAbsolutePath();
-                       }
-                       return names;
-               } else if (System.getProperty("os.name").equals("Windows NT")) {  //$NON-NLS-1$//$NON-NLS-2$
-//                     WindowsRegistry reg = WindowsRegistry.getRegistry();
-//                     if (reg != null) {
-//                             List<String> ports = new ArrayList<>();
-//                             int i = 0;
-//                             String name = reg.getLocalMachineValueName(SERIAL_KEY, i);
-//                             while (name != null) {
-//                                     String value = reg.getLocalMachineValue(SERIAL_KEY, name);
-//                                     ports.add(value);
-//                                     i++;
-//                                     name = reg.getLocalMachineValueName(SERIAL_KEY, i);
-//                             }
-//                             return ports.toArray(new String[ports.size()]);
-//                     } else {
-//                             return new String[0];
-//                     }
-                       return new String[0];
+                       return ports.toArray(new String[ports.size()]);
                } else {
                        return new String[0];
                }
        }
 
-       private native long open0(String portName, int baudRate, int byteSize, int parity, int stopBits) throws IOException;
-
-       private native void close0(long handle) throws IOException;
-
-       private native int read0(long handle) throws IOException;
-
-       private native int read1(long handle, byte[] b, int off, int len);
-
-       private native void write0(long handle, int b) throws IOException;
-
        /**
         * Return the name for this serial port.
         *