Skip to content

Commit

Permalink
Merge pull request #4 from umjammer/0.14.4v
Browse files Browse the repository at this point in the history
0.14.4v
  • Loading branch information
umjammer committed Dec 27, 2023
2 parents 51bdae5 + dfedd8f commit 72c67c8
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 47 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>org.hid4java</groupId>
<artifactId>hid4java</artifactId>
<version>0.14.3v</version>
<version>0.14.4v</version>

<name>hid4java</name>
<description>A cross-platform Java Native Access (JNA) wrapper for the libusb/hidapi library</description>
Expand Down
21 changes: 19 additions & 2 deletions src/main/java/org/hid4java/HidDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.io.IOException;
import java.util.Arrays;
import java.util.StringJoiner;
import java.util.logging.Logger;


Expand Down Expand Up @@ -130,6 +131,22 @@ public enum HidBusType {
* Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
*/
public HidBusType busType;

@Override public String toString() {
return new StringJoiner(", ", Info.class.getSimpleName() + "[", "]")
.add("path='" + path + "'")
.add("vendorId=" + vendorId)
.add("productId=" + productId)
.add("serialNumber='" + serialNumber + "'")
.add("releaseNumber=" + releaseNumber)
.add("manufacturer='" + manufacturer + "'")
.add("product='" + product + "'")
.add("usagePage=" + usagePage)
.add("usage=" + usage)
.add("interfaceNumber=" + interfaceNumber)
.add("busType=" + busType)
.toString();
}
}

private final boolean autoDataRead;
Expand Down Expand Up @@ -158,7 +175,7 @@ public HidDevice(Info info, org.hid4java.HidDeviceManager deviceManager, HidServ
this.info.productId = this.info.productId & 0xffff;

nativeDevice = manager.open(info);
logger.finer(getPath() + "(@" + hashCode() + "): " + nativeDevice);
logger.finest(getPath() + "(@" + hashCode() + "): " + nativeDevice);
}

/**
Expand Down Expand Up @@ -274,7 +291,7 @@ public boolean isOpen() {
* @since 0.1.0
*/
public void close() throws IOException {
logger.finer("close native: " + nativeDevice);
logger.finest("close native: " + nativeDevice);
// Close the Hidapi reference
nativeDevice.close();
isOpen = false;
Expand Down
17 changes: 13 additions & 4 deletions src/main/java/org/hid4java/HidDeviceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public class HidDeviceManager {
* We use a Thread instead of Executor since it may be stopped/paused/restarted frequently
* and executors are more heavyweight in this regard
*/
private final ExecutorService scanThread = Executors.newSingleThreadExecutor();
private ExecutorService scanThread;

/**
* Constructs a new device manager
Expand Down Expand Up @@ -130,6 +130,8 @@ public class HidDeviceManager {
*/
public void start() throws IOException {

nativeManager.open();

// Check for previous start
if (this.isScanning()) {
return;
Expand Down Expand Up @@ -177,7 +179,7 @@ public synchronized void scan() throws IOException {

if (!this.attachedDevices.containsKey(attachedDevice.getId())) {

logger.finer("device: " + attachedDevice.getProductId() + "," + attachedDevice);
logger.finest("device: " + attachedDevice.getProductId() + "," + attachedDevice);
// Device has become attached so add it but do not create
attachedDevices.put(attachedDevice.getId(), attachedDevice);

Expand Down Expand Up @@ -211,7 +213,7 @@ public synchronized void scan() throws IOException {
* @return True if the scan thread is running, false otherwise.
*/
public boolean isScanning() {
return !scanThread.isTerminated();
return scanThread != null && !scanThread.isTerminated();
}

/**
Expand Down Expand Up @@ -269,6 +271,7 @@ private synchronized void stopScanThread() {

if (isScanning()) {
scanThread.shutdownNow();
scanThread = null;
}
}

Expand All @@ -281,6 +284,8 @@ private synchronized void configureScanThread(Runnable scanRunnable) {
stopScanThread();
}

scanThread = Executors.newSingleThreadExecutor();

// Require a new one
scanThread.submit(scanRunnable);
}
Expand Down Expand Up @@ -345,7 +350,11 @@ private synchronized Runnable getScanRunnable() {

public void shutdown() {
logger.finer("shutdown.0");
nativeManager.close();
if (isScanning()) {
stopScanThread();
}
logger.finer("shutdown.1");
nativeManager.close();
logger.finer("shutdown.2");
}
}
10 changes: 8 additions & 2 deletions src/main/java/org/hid4java/HidServices.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,19 @@ public HidServices(HidServicesSpecification hidServicesSpecification) throws IOE
* Stop all device threads and shut down the {@link NativeHidDevice}
*/
public void shutdown() {
logger.finer("shutdown: start");
logger.finer("shutdown: start shutdown...");
//new Exception().printStackTrace();
try {
stop();
} catch (Throwable e) {
// Silently fail (user will already have been given an exception)
logger.log(Level.FINER, e.getMessage(), e);
}
try {
hidDeviceManager.shutdown();
} catch (Throwable e) {
// Silently fail (user will already have been given an exception)
logger.log(Level.FINER, e.getMessage(), e);
}
if (logger.isLoggable(Level.FINER)) {
Thread.getAllStackTraces().keySet().forEach(System.err::println);
Expand All @@ -122,7 +128,7 @@ public void shutdown() {
* Normally part of an application shutdown
*/
public void stop() throws IOException {
logger.finer("stop: start");
logger.finer("stop: start stopping...");
hidDeviceManager.stop();
this.listeners.clear();
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/hid4java/NativeHidDeviceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
*/
public interface NativeHidDeviceManager {

/**
* As an initializer (this instance is used as a service provider, so the instance is reused)
*/
void open();

/**
* Finalize the HIDAPI library.
* <p>
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/hid4java/linux/LinuxHidDeviceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,10 @@ static HidDevice.Info create_device_info_for_device(Udev.UdevDevice rawDev) thro
return root.get(0);
}

@Override
public void open() {
}

@Override
public void close() {
}
Expand Down
79 changes: 46 additions & 33 deletions src/main/java/org/hid4java/macos/MacosHidDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,10 @@ private static void onReportCallback(Pointer context, int /* IOReturn */ result,
}

private void internalOpen() throws IOException {
if (deviceHandle != null) {
return;
}
if (deviceHandle != null) {
logger.warning("deviceHandle is not null");
return;
}

Pointer/* io_registry_entry_t */ entry = null;
try {
Expand Down Expand Up @@ -312,38 +313,51 @@ public void open() throws IOException {

@Override
public void close() {
logger.finer("here20.0: " + deviceInfo.path);

// Disconnect the report callback before close.
// See comment below.
if (MacosHidDeviceManager.is_macos_10_10_or_greater || !this.disconnected) {
logger.finest("here20.0: " + deviceInfo);
if (this.deviceHandle == null) {
logger.finest("not opened");
return;
}

logger.finer("here20.1: removal callback null, unschedule run loop start");
IOKitLib.INSTANCE.IOHIDDeviceRegisterInputReportCallback(
this.deviceHandle.device, this.inputReportBuffer, CFIndex.of(this.maxInputReportLength),
null, null);
IOKitLib.INSTANCE.IOHIDDeviceRegisterRemovalCallback(this.deviceHandle.device, null, null);
IOKitLib.INSTANCE.IOHIDDeviceUnscheduleFromRunLoop(this.deviceHandle.device, this.runLoop, this.runLoopMode);
IOKitLib.INSTANCE.IOHIDDeviceScheduleWithRunLoop(this.deviceHandle.device, CFLib.INSTANCE.CFRunLoopGetMain(), kCFRunLoopDefaultMode);
logger.finer("here20.0.1: source: " + this.source + ", thread: " + this.thread);
if (this.thread != null) { // when not #open()
// Disconnect the report callback before close.
// See comment below.
if (MacosHidDeviceManager.is_macos_10_10_or_greater || !this.disconnected) {

logger.finer("here20.1: removal callback null, unschedule run loop start: " + this.deviceHandle.device);
IOKitLib.INSTANCE.IOHIDDeviceRegisterInputReportCallback(
this.deviceHandle.device, this.inputReportBuffer, CFIndex.of(this.maxInputReportLength),
null, null);
IOKitLib.INSTANCE.IOHIDDeviceRegisterRemovalCallback(this.deviceHandle.device, null, null);
IOKitLib.INSTANCE.IOHIDDeviceUnscheduleFromRunLoop(this.deviceHandle.device, this.runLoop, this.runLoopMode);
IOKitLib.INSTANCE.IOHIDDeviceScheduleWithRunLoop(this.deviceHandle.device, CFLib.INSTANCE.CFRunLoopGetMain(), kCFRunLoopDefaultMode);
logger.finer("here20.2: removal callback null, unschedule run loop done");
}
}

// Cause read_thread() to stop.
this.shutdownThread = true;
// Cause read_thread() to stop.
this.shutdownThread = true;

// Wake up the run thread's event loop so that the thread can close.
CFLib.INSTANCE.CFRunLoopSourceSignal(this.source);
CFLib.INSTANCE.CFRunLoopWakeUp(this.runLoop);
logger.finest("here20.3: wake up run loop: @" + this.runLoop.hashCode()); // TODO <- not here, until 20.2
// Wake up the run thread's event loop so that the thread can close.
CFLib.INSTANCE.CFRunLoopSourceSignal(this.source);
CFLib.INSTANCE.CFRunLoopWakeUp(this.runLoop);
logger.finest("here20.3: wake up run loop: @" + this.runLoop.hashCode());

// Notify the read thread that it can shut down now.
// Notify the read thread that it can shut down now.
logger.finer("here20.4: " + Thread.currentThread() + ", " + this.thread);
logger.finest("here20.5: notify shutdownBarrier -1");
this.shutdownBarrier.waitAndSync();
this.shutdownBarrier.waitAndSync();

// Wait for read_thread() to end.
// Wait for read_thread() to end.
logger.finer("here20.6: join...: " + this.thread);
try { this.thread.join(); } catch (InterruptedException ignore) {}
try {
this.thread.join();
} catch (InterruptedException ignore) {
}

CFLib.INSTANCE.CFRelease(this.runLoopMode);
CFLib.INSTANCE.CFRelease(this.source);
}

// Close the OS handle to the device, but only if it's not
// been unplugged. If it's been unplugged, then calling
Expand All @@ -354,18 +368,17 @@ public void close() {
// crash happenes if IOHIDDeviceClose() is not called.
// Not leaking a resource in all tested environments.

logger.finer("here20.7.0: native device: " + this.deviceHandle.device);
if (MacosHidDeviceManager.is_macos_10_10_or_greater || !this.disconnected) {
logger.finer("here20.7.1: native device: " + this.deviceHandle.device);
IOKitLib.INSTANCE.IOHIDDeviceClose(this.deviceHandle.device, kIOHIDOptionsTypeSeizeDevice);
logger.finer("here20.7: native device close: @" + this.deviceHandle.device.hashCode());
logger.finer("here20.7.2: native device close: @" + this.deviceHandle.device.hashCode());
}

if (this.runLoopMode != null)
CFLib.INSTANCE.CFRelease(this.runLoopMode);
if (this.source != null)
CFLib.INSTANCE.CFRelease(this.source);

logger.finest("here20.8.1: native device release");
CFLib.INSTANCE.CFRelease(this.deviceHandle.device);
logger.finest("here20.8: native device release");
logger.finest("here20.8.2: native device release");
deviceHandle = null;

closer.accept(this.deviceInfo.path);
logger.finer("here20.9: close done");
Expand Down
18 changes: 13 additions & 5 deletions src/main/java/org/hid4java/macos/MacosHidDeviceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
Expand Down Expand Up @@ -108,7 +109,10 @@ private void hid_darwin_set_open_exclusive(boolean openExclusive) {
public MacosHidDeviceManager() {
logger.finer("is_macos_10_10_or_greater: " + is_macos_10_10_or_greater);
hid_darwin_set_open_exclusive(!darwinOpenDevicesNonExclusive); // Backward compatibility
}

@Override
public void open() {
manager = IOKitLib.INSTANCE.IOHIDManagerCreate(CFAllocator.kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (manager != null) {
IOKitLib.INSTANCE.IOHIDManagerSetDeviceMatching(manager, null);
Expand All @@ -119,9 +123,13 @@ public MacosHidDeviceManager() {
}

@Override
@SuppressWarnings("WhileLoopReplaceableByForEach") // for ConcurrentModificationException
public void close() {
logger.finer("here10.0: hid_exit");
devices.values().forEach(MacosHidDevice::close);
Iterator<MacosHidDevice> i = devices.values().iterator();
while (i.hasNext()) {
i.next().close();
}

if (manager != null) {
/* Close the HID manager. */
Expand Down Expand Up @@ -208,7 +216,7 @@ public List<HidDevice.Info> enumerate(int vendorId, int productId) throws IOExce
CFLib.INSTANCE.CFRelease(p);
}
}
logger.finest("here7.0: " + matching + ", " + Thread.currentThread());
logger.finest("here7.0: " + matching + ", " + Thread.currentThread() + ", " + manager);
IOKitLib.INSTANCE.IOHIDManagerSetDeviceMatching(manager, matching);
if (matching != null) {
logger.finer("here7.1: matching null");
Expand Down Expand Up @@ -263,10 +271,10 @@ public List<HidDevice.Info> enumerate(int vendorId, int productId) throws IOExce

@Override
public MacosHidDevice create(HidDevice.Info info) throws IOException {
logger.finer("here00.0: path: " + info.path);
logger.finest("here00.0: path: " + info.path);
MacosHidDevice device = devices.get(info.path);
if (device != null) {
logger.finer("here00.1: devices: cached: " + device);
logger.finest("here00.1: devices: cached: " + device);
device.deviceInfo = info;
return device;
}
Expand All @@ -276,7 +284,7 @@ public MacosHidDevice create(HidDevice.Info info) throws IOException {

device.closer = devices::remove;
devices.put(device.deviceInfo.path, device);
logger.finer("here00.E: devices: +: " + device.deviceInfo.path + " / " + devices.size());
logger.finest("here00.E: devices: +: " + device.deviceInfo.path + " / " + devices.size());
return device;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ private HidDevice.Info hid_internal_get_device_info(String path, HANDLE handle)
return dev;
}

@Override
public void open() {
}

@Override
public void close() {
}
Expand Down

0 comments on commit 72c67c8

Please sign in to comment.