From f1bee2adabc7ff0d166f0c7d9c7946e78649355c Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 31 Mar 2016 18:00:01 +0200 Subject: [PATCH 1/4] add usbSearch as submodule --- .gitmodules | 3 ++ compile_win.sh | 8 ++--- jnilib.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ usbSearch | 1 + 4 files changed, 88 insertions(+), 4 deletions(-) create mode 160000 usbSearch diff --git a/.gitmodules b/.gitmodules index 29ebbb6..04b95ec 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "libserialport"] path = libserialport url = https://github.com/facchinm/libserialport.git +[submodule "usbSearch"] + path = usbSearch + url = https://github.com/todbot/usbSearch.git diff --git a/compile_win.sh b/compile_win.sh index 66fbe92..4667af7 100755 --- a/compile_win.sh +++ b/compile_win.sh @@ -4,12 +4,12 @@ JAVA_INCLUDE_PATH=/opt/jvm/jdk1.8.0/include/ mkdir -p distrib/windows cd libserialport -./autogen.sh -./configure --host=i686-w64-mingw32 +#./autogen.sh +#./configure --host=i686-w64-mingw32 make clean make cd .. i686-w64-mingw32-gcc main.c -Llibserialport/.libs/ -Ilibserialport/ -lserialport -lsetupapi -static -o listSerialC.exe cp listSerialC.exe distrib/windows/ -i686-w64-mingw32-gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at jnilib.c libserialport/.libs/libserialport.a -lsetupapi -Ilibserialport/ -I/opt/jvm/jdk1.8.0/include/ -Iwin32_jni -shared -o listSerialsj.dll -cp listSerialsj.dll distrib/windows/ \ No newline at end of file +i686-w64-mingw32-gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at jnilib.c usbSearch/disphelper.c libserialport/.libs/libserialport.a -lhid -lsetupapi -lole32 -loleaut32 -luuid -Ilibserialport/ -IusbSearch -I/opt/jvm/jdk1.8.0/include/ -Iwin32_jni -shared -o listSerialsj.dll +cp listSerialsj.dll distrib/windows/ diff --git a/jnilib.c b/jnilib.c index 5487d00..9dba694 100644 --- a/jnilib.c +++ b/jnilib.c @@ -25,6 +25,8 @@ JNIEXPORT jstring JNICALL Java_processing_app_Platform_resolveDeviceAttachedToNa return (*env)->NewStringUTF(env, vid_pid_iserial); } +#ifndef _WIN32 + JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative (JNIEnv * env, jobject jobj) { @@ -56,3 +58,81 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative return ret; } + +#else + +// use listcomports code +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + +JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative + (JNIEnv * env, jobject jobj) +{ + jobjectArray ret; + char portname_vid_pid[256] = " "; + DISPATCH_OBJ(wmiSvc); + DISPATCH_OBJ(colDevices); + + dhInitialize(TRUE); + dhToggleExceptions(TRUE); + + dhGetObject(L"winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2", + //dhGetObject(L"winmgmts:\\\\.\\root\\cimv2", + NULL, &wmiSvc); + dhGetValue(L"%o", &colDevices, wmiSvc, + L".ExecQuery(%S)", + L"Select * from Win32_PnPEntity"); + + int port_count, vid, pid, i = 0; + + struct sp_port **ports; + sp_list_ports(&ports); + + // like ports.size() + for (i = 0; ports[i]; i++) {}; + sp_free_port_list(ports); + + ret = (jobjectArray)(*env)->NewObjectArray(env, i, (*env)->FindClass(env, "java/lang/String"), (*env)->NewStringUTF(env, "")); + + FOR_EACH(objDevice, colDevices, NULL) { + char* name = NULL; + char* pnpid = NULL; + char* match; + + dhGetValue(L"%s", &name, objDevice, L".Name"); + dhGetValue(L"%s", &pnpid, objDevice, L".PnPDeviceID"); + + if( name != NULL && ((match = strstr( name, "(COM" )) != NULL) ) { // look for "(COM23)" + // 'Manufacturuer' can be null, so only get it if we need it + char* comname = strtok( match, "()"); + sscanf(pnpid, "%*sVID_%4x%*s", vid); + sscanf(pnpid, "%*sPID_%4x%*s", pid); + snprintf(portname_vid_pid, sizeof(portname_vid_pid), "%s_%04X_%04X", comname, vid, pid); + printf("%s - %s\n", portname_vid_pid, pnpid); + (*env)->SetObjectArrayElement(env, ret, port_count, (*env)->NewStringUTF(env, portname_vid_pid)); + port_count++; + } + dhFreeString(name); + dhFreeString(pnpid); + + } NEXT(objDevice); + + SAFE_RELEASE(colDevices); + SAFE_RELEASE(wmiSvc); + + dhUninitialize(TRUE); + + return ret; +} + +#endif \ No newline at end of file diff --git a/usbSearch b/usbSearch new file mode 160000 index 0000000..943fe98 --- /dev/null +++ b/usbSearch @@ -0,0 +1 @@ +Subproject commit 943fe9878974e1e3cd352ad441d534198565f86e From b607e9d6eb6885e9f0df34709f644f3ab472c697 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 1 Apr 2016 09:49:16 +0200 Subject: [PATCH 2/4] use usbSearch method for polling on windows solves arduino/Arduino#4777 --- .gitmodules | 2 +- jnilib.c | 21 +++++++++++++++------ usbSearch | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.gitmodules b/.gitmodules index 04b95ec..504003b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/facchinm/libserialport.git [submodule "usbSearch"] path = usbSearch - url = https://github.com/todbot/usbSearch.git + url = https://github.com/arduino/usbSearch.git diff --git a/jnilib.c b/jnilib.c index 9dba694..212e2c8 100644 --- a/jnilib.c +++ b/jnilib.c @@ -84,7 +84,7 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative DISPATCH_OBJ(colDevices); dhInitialize(TRUE); - dhToggleExceptions(TRUE); + dhToggleExceptions(FALSE); dhGetObject(L"winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2", //dhGetObject(L"winmgmts:\\\\.\\root\\cimv2", @@ -93,7 +93,10 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative L".ExecQuery(%S)", L"Select * from Win32_PnPEntity"); - int port_count, vid, pid, i = 0; + int port_count = 0; + int vid = 0; + int pid = 0; + int i = 0; struct sp_port **ports; sp_list_ports(&ports); @@ -113,12 +116,18 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative dhGetValue(L"%s", &pnpid, objDevice, L".PnPDeviceID"); if( name != NULL && ((match = strstr( name, "(COM" )) != NULL) ) { // look for "(COM23)" - // 'Manufacturuer' can be null, so only get it if we need it char* comname = strtok( match, "()"); - sscanf(pnpid, "%*sVID_%4x%*s", vid); - sscanf(pnpid, "%*sPID_%4x%*s", pid); + char id_s[5]; + char * pch; + pch = strstr (pnpid,"VID_"); + strncpy(id_s, pch + 4, 4); + vid = strtol(id_s, NULL, 16); + pch = strstr (pnpid,"PID_"); + strncpy(id_s, pch + 4, 4); + pid = strtol(id_s, NULL, 16); + //sscanf(pnpid, "%*sVID_%4X", vid); + //sscanf(pnpid, "%*sPID_%4X", pid); snprintf(portname_vid_pid, sizeof(portname_vid_pid), "%s_%04X_%04X", comname, vid, pid); - printf("%s - %s\n", portname_vid_pid, pnpid); (*env)->SetObjectArrayElement(env, ret, port_count, (*env)->NewStringUTF(env, portname_vid_pid)); port_count++; } diff --git a/usbSearch b/usbSearch index 943fe98..098b807 160000 --- a/usbSearch +++ b/usbSearch @@ -1 +1 @@ -Subproject commit 943fe9878974e1e3cd352ad441d534198565f86e +Subproject commit 098b807b163905a64b32cd7b51da165c2a612a24 From cc6d1131d236cdf904c298a5286149cac938ae38 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 1 Apr 2016 10:20:55 +0200 Subject: [PATCH 3/4] safer array handling since operations are not atomic i and port_count can be different Always fill the array to its maximum --- compile_win.sh | 4 ++-- jnilib.c | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compile_win.sh b/compile_win.sh index 4667af7..d6242d9 100755 --- a/compile_win.sh +++ b/compile_win.sh @@ -4,8 +4,8 @@ JAVA_INCLUDE_PATH=/opt/jvm/jdk1.8.0/include/ mkdir -p distrib/windows cd libserialport -#./autogen.sh -#./configure --host=i686-w64-mingw32 +./autogen.sh +./configure --host=i686-w64-mingw32 make clean make cd .. diff --git a/jnilib.c b/jnilib.c index 212e2c8..3d3eb8c 100644 --- a/jnilib.c +++ b/jnilib.c @@ -128,7 +128,10 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative //sscanf(pnpid, "%*sVID_%4X", vid); //sscanf(pnpid, "%*sPID_%4X", pid); snprintf(portname_vid_pid, sizeof(portname_vid_pid), "%s_%04X_%04X", comname, vid, pid); - (*env)->SetObjectArrayElement(env, ret, port_count, (*env)->NewStringUTF(env, portname_vid_pid)); + if (port_count < i) { + // only store element if safe (operations are not atomic) + (*env)->SetObjectArrayElement(env, ret, port_count, (*env)->NewStringUTF(env, portname_vid_pid)); + } port_count++; } dhFreeString(name); @@ -136,6 +139,11 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative } NEXT(objDevice); + for (; port_count < i; port_count++) { + // fill the array with copies of the last good value (operations are not atomic) + (*env)->SetObjectArrayElement(env, ret, port_count, (*env)->NewStringUTF(env, portname_vid_pid)); + } + SAFE_RELEASE(colDevices); SAFE_RELEASE(wmiSvc); From 015bc53030c4c904f83d0f83ee84b42ddb836a63 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 1 Apr 2016 17:12:26 +0200 Subject: [PATCH 4/4] check return value of all libserial API --- jnilib.c | 17 ++++++++++++----- main.c | 6 +++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/jnilib.c b/jnilib.c index 3d3eb8c..d6dd4e2 100644 --- a/jnilib.c +++ b/jnilib.c @@ -12,7 +12,9 @@ JNIEXPORT jstring JNICALL Java_processing_app_Platform_resolveDeviceAttachedToNa const char *portname = (*env)->GetStringUTFChars(env, serial, NULL); jstring result; - sp_get_port_by_name(portname, &port); + if (sp_get_port_by_name(portname, &port) != SP_OK) { + return (*env)->NewStringUTF(env, ""); + } int vid, pid; if (sp_get_port_usb_vid_pid(port, &vid, &pid) == SP_OK) { @@ -36,7 +38,9 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative char portname_vid_pid[256] = " "; - sp_list_ports(&ports); + if (sp_list_ports(&ports) != SP_OK) { + return (jobjectArray)(*env)->NewObjectArray(env, 0, (*env)->FindClass(env, "java/lang/String"), (*env)->NewStringUTF(env, ""));; + } // like ports.size() for (i = 0; ports[i]; i++) {}; @@ -80,6 +84,12 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative { jobjectArray ret; char portname_vid_pid[256] = " "; + + struct sp_port **ports; + if (sp_list_ports(&ports) != SP_OK) { + return (jobjectArray)(*env)->NewObjectArray(env, 0, (*env)->FindClass(env, "java/lang/String"), (*env)->NewStringUTF(env, ""));; + } + DISPATCH_OBJ(wmiSvc); DISPATCH_OBJ(colDevices); @@ -98,9 +108,6 @@ JNIEXPORT jobjectArray JNICALL Java_processing_app_Platform_listSerialsNative int pid = 0; int i = 0; - struct sp_port **ports; - sp_list_ports(&ports); - // like ports.size() for (i = 0; ports[i]; i++) {}; sp_free_port_list(ports); diff --git a/main.c b/main.c index 39c8d25..c3bc647 100644 --- a/main.c +++ b/main.c @@ -5,8 +5,12 @@ int main(void) { int i; struct sp_port **ports; + enum sp_return ret; - sp_list_ports(&ports); + ret = sp_list_ports(&ports); + if (ret != SP_OK) { + return 0; + } for (i = 0; ports[i]; i++) { int vid, pid;