From 65819ae7c10ea5327c63ebccd7de7a57faaf762b Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Mon, 31 Jan 2011 20:10:19 +0100 Subject: [PATCH] JSR 80: Implemented device scanning. Added hashcode/equals methods. --- src/main/java/de/ailis/usb4java/USB_Bus.java | 31 ++++ .../ailis/usb4java/USB_Config_Descriptor.java | 42 ++++++ .../ailis/usb4java/USB_Descriptor_Header.java | 34 ++++- .../java/de/ailis/usb4java/USB_Device.java | 33 ++++- .../ailis/usb4java/USB_Device_Descriptor.java | 52 +++++++ .../usb4java/USB_Endpoint_Descriptor.java | 42 ++++++ .../usb4java/USB_Interface_Descriptor.java | 45 ++++++ .../ailis/usb4java/USB_String_Descriptor.java | 31 ++++ .../jsr80/UsbConfigurationDescriptorImpl.java | 26 ++++ .../usb4java/jsr80/UsbDescriptorImpl.java | 26 ++++ .../jsr80/UsbDeviceDescriptorImpl.java | 26 ++++ .../ailis/usb4java/jsr80/UsbDeviceImpl.java | 102 ++++++++++++- .../usb4java/jsr80/UsbDeviceScanner.java | 138 +++++++++++++++--- .../jsr80/UsbEndpointDescriptorImpl.java | 26 ++++ .../jsr80/UsbInterfaceDescriptorImpl.java | 26 ++++ .../de/ailis/usb4java/jsr80/UsbPortImpl.java | 3 + .../ailis/usb4java/jsr80/UsbServicesImpl.java | 32 +++- .../jsr80/UsbServicesListenerList.java | 2 +- .../jsr80/UsbStringDescriptorImpl.java | 27 ++++ src/test/java/Test.java | 52 ------- 20 files changed, 708 insertions(+), 88 deletions(-) delete mode 100644 src/test/java/Test.java diff --git a/src/main/java/de/ailis/usb4java/USB_Bus.java b/src/main/java/de/ailis/usb4java/USB_Bus.java index 670acb9..a14834b 100644 --- a/src/main/java/de/ailis/usb4java/USB_Bus.java +++ b/src/main/java/de/ailis/usb4java/USB_Bus.java @@ -127,4 +127,35 @@ public final class USB_Bus { return dirname(); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object obj) + { + if (obj == null) return false; + if (obj == this) return true; + if (obj.getClass() != getClass()) return false; + final USB_Bus other = (USB_Bus) obj; + return dirname().equals(other.dirname()) + && location() == other.location(); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + dirname().hashCode(); + final long location = location(); + result = 37 * result + (int) (location ^ (location >>> 32)); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/USB_Config_Descriptor.java b/src/main/java/de/ailis/usb4java/USB_Config_Descriptor.java index 4b7d986..9d5e3fd 100644 --- a/src/main/java/de/ailis/usb4java/USB_Config_Descriptor.java +++ b/src/main/java/de/ailis/usb4java/USB_Config_Descriptor.java @@ -175,4 +175,46 @@ public final class USB_Config_Descriptor extends USB_Descriptor_Header } return builder.toString(); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (o == this) return true; + if (o.getClass() != getClass()) return false; + final USB_Config_Descriptor other = (USB_Config_Descriptor) o; + return super.equals(o) + && bConfigurationValue() == other.bConfigurationValue() + && bmAttributes() == other.bmAttributes() + && bNumInterfaces() == other.bNumInterfaces() + && iConfiguration() == other.iConfiguration() + && MaxPower() == other.MaxPower() + && wTotalLength() == other.wTotalLength(); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + super.hashCode(); + result = 37 * result + bConfigurationValue(); + result = 37 * result + bmAttributes(); + result = 37 * result + bNumInterfaces(); + result = 37 * result + iConfiguration(); + result = 37 * result + MaxPower(); + result = 37 * result + wTotalLength(); + result = 37 * result + extralen(); + result = 37 * result + extra().hashCode(); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/USB_Descriptor_Header.java b/src/main/java/de/ailis/usb4java/USB_Descriptor_Header.java index 38333b5..e783771 100644 --- a/src/main/java/de/ailis/usb4java/USB_Descriptor_Header.java +++ b/src/main/java/de/ailis/usb4java/USB_Descriptor_Header.java @@ -9,8 +9,8 @@ import java.nio.ByteBuffer; /** - * All standard descriptors have the two fields bLength and bDescriptorType - * in common. So this base class implements them. + * All standard descriptors have the two fields bLength and bDescriptorType in + * common. So this base class implements them. * * @author Klaus Reimer (k@ailis.de) */ @@ -50,4 +50,34 @@ public abstract class USB_Descriptor_Header */ public final native int bDescriptorType(); + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (o == this) return true; + if (o.getClass() != getClass()) return false; + final USB_Device_Descriptor other = (USB_Device_Descriptor) o; + return bDescriptorType() == other.bDescriptorType() && + bLength() == other.bLength(); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + bDescriptorType(); + result = 37 * result + bLength(); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/USB_Device.java b/src/main/java/de/ailis/usb4java/USB_Device.java index 1b50136..1641a4b 100644 --- a/src/main/java/de/ailis/usb4java/USB_Device.java +++ b/src/main/java/de/ailis/usb4java/USB_Device.java @@ -163,6 +163,37 @@ public final class USB_Device @Override public String toString() { - return bus().dirname() + "/" + filename(); + return bus().dirname() + "/" + filename(); + } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object obj) + { + if (obj == null) return false; + if (obj == this) return true; + if (obj.getClass() != getClass()) return false; + final USB_Device other = (USB_Device) obj; + return bus().equals(other.bus()) && filename().equals(other.filename()) + && descriptor().equals(other.descriptor()); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + bus().hashCode(); + result = 37 * result + filename().hashCode(); + result = 37 * result + descriptor().hashCode(); + return result; } } diff --git a/src/main/java/de/ailis/usb4java/USB_Device_Descriptor.java b/src/main/java/de/ailis/usb4java/USB_Device_Descriptor.java index 7f1d540..aaaafec 100644 --- a/src/main/java/de/ailis/usb4java/USB_Device_Descriptor.java +++ b/src/main/java/de/ailis/usb4java/USB_Device_Descriptor.java @@ -233,4 +233,56 @@ public final class USB_Device_Descriptor extends USB_Descriptor_Header iProduct, sProduct, iSerialNumber, sSerialNumber, bNumConfigurations()); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (o == this) return true; + if (o.getClass() != getClass()) return false; + final USB_Device_Descriptor other = (USB_Device_Descriptor) o; + return super.equals(o) && idProduct() == other.idProduct() + && idVendor() == other.idVendor() + && bcdDevice() == other.bcdDevice() && bcdUSB() == other.bcdUSB() + && bDescriptorType() == other.bDescriptorType() + && bDeviceClass() == other.bDeviceClass() + && bDeviceProtocol() == other.bDeviceProtocol() + && bDeviceSubClass() == other.bDeviceSubClass() + && bLength() == other.bLength() + && bMaxPacketSize0() == other.bMaxPacketSize0() + && bNumConfigurations() == other.bNumConfigurations() + && iManufacturer() == other.iManufacturer() + && iProduct() == other.iProduct() + && iSerialNumber() == other.iSerialNumber(); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + super.hashCode(); + result = 37 * result + idProduct(); + result = 37 * result + idVendor(); + result = 37 * result + bcdDevice(); + result = 37 * result + bcdUSB(); + result = 37 * result + bDeviceClass(); + result = 37 * result + bDeviceProtocol(); + result = 37 * result + bDeviceSubClass(); + result = 37 * result + bMaxPacketSize0(); + result = 37 * result + bNumConfigurations(); + result = 37 * result + iManufacturer(); + result = 37 * result + iProduct(); + result = 37 * result + iSerialNumber(); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/USB_Endpoint_Descriptor.java b/src/main/java/de/ailis/usb4java/USB_Endpoint_Descriptor.java index 579f906..91b50c6 100644 --- a/src/main/java/de/ailis/usb4java/USB_Endpoint_Descriptor.java +++ b/src/main/java/de/ailis/usb4java/USB_Endpoint_Descriptor.java @@ -150,4 +150,46 @@ public final class USB_Endpoint_Descriptor extends USB_Descriptor_Header wMaxPacketSize(), bInterval(), extralen(), USBUtils.toHexDump(extra(), 16).replaceAll("(?m)^", " ")); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (o == this) return true; + if (o.getClass() != getClass()) return false; + final USB_Endpoint_Descriptor other = (USB_Endpoint_Descriptor) o; + return super.equals(o) + && bEndpointAddress() == other.bEndpointAddress() + && bmAttributes() == other.bmAttributes() + && bInterval() == other.bInterval() + && bSynchAddress() == other.bSynchAddress() + && wMaxPacketSize() == other.wMaxPacketSize() + && extralen() == other.extralen() + && extra().equals(other.extra()); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + super.hashCode(); + result = 37 * result + bEndpointAddress(); + result = 37 * result + bInterval(); + result = 37 * result + bRefresh(); + result = 37 * result + bSynchAddress(); + result = 37 * result + wMaxPacketSize(); + result = 37 * result + extralen(); + result = 37 * result + extra().hashCode(); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/USB_Interface_Descriptor.java b/src/main/java/de/ailis/usb4java/USB_Interface_Descriptor.java index 09f8708..4845f11 100644 --- a/src/main/java/de/ailis/usb4java/USB_Interface_Descriptor.java +++ b/src/main/java/de/ailis/usb4java/USB_Interface_Descriptor.java @@ -188,4 +188,49 @@ public final class USB_Interface_Descriptor extends USB_Descriptor_Header } return builder.toString(); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (o == this) return true; + if (o.getClass() != getClass()) return false; + final USB_Interface_Descriptor other = (USB_Interface_Descriptor) o; + return super.equals(o) + && bAlternateSetting() == other.bAlternateSetting() + && bInterfaceClass() == other.bInterfaceClass() + && bInterfaceNumber() == other.bInterfaceNumber() + && bInterfaceProtocol() == other.bInterfaceProtocol() + && bInterfaceSubClass() == other.bInterfaceSubClass() + && bNumEndpoints() == other.bNumEndpoints() + && iInterface() == other.iInterface() + && extralen() == other.extralen() + && extra().equals(other.extra()); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + super.hashCode(); + result = 37 * result + bAlternateSetting(); + result = 37 * result + bInterfaceClass(); + result = 37 * result + bInterfaceProtocol(); + result = 37 * result + bInterfaceSubClass(); + result = 37 * result + bNumEndpoints(); + result = 37 * result + iInterface(); + result = 37 * result + extralen(); + result = 37 * result + extra().hashCode(); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/USB_String_Descriptor.java b/src/main/java/de/ailis/usb4java/USB_String_Descriptor.java index 4423cbd..8295f23 100644 --- a/src/main/java/de/ailis/usb4java/USB_String_Descriptor.java +++ b/src/main/java/de/ailis/usb4java/USB_String_Descriptor.java @@ -8,6 +8,7 @@ package de.ailis.usb4java; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; +import java.util.Arrays; /** @@ -57,4 +58,34 @@ public final class USB_String_Descriptor extends USB_Descriptor_Header { return new String(wData()); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (o == this) return true; + if (o.getClass() != getClass()) return false; + final USB_String_Descriptor other = (USB_String_Descriptor) o; + return super.equals(o) + && Arrays.equals(wData(), other.wData()); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + int result = 17; + result = 37 * result + super.hashCode(); + result = 37 * result + Arrays.hashCode(wData()); + return result; + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationDescriptorImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationDescriptorImpl.java index 344a690..df9e247 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationDescriptorImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationDescriptorImpl.java @@ -97,4 +97,30 @@ public final class UsbConfigurationDescriptorImpl extends { return (byte) (this.descriptor.MaxPower() & 0xff); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final UsbConfigurationDescriptorImpl other = (UsbConfigurationDescriptorImpl) o; + return this.descriptor.equals(other.descriptor); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.descriptor.hashCode(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbDescriptorImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbDescriptorImpl.java index 745447f..954e6fe 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbDescriptorImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbDescriptorImpl.java @@ -58,4 +58,30 @@ public abstract class UsbDescriptorImpl { return (byte) (this.descriptor.bDescriptorType() & 0xff); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final UsbDescriptorImpl other = (UsbDescriptorImpl) o; + return this.descriptor.equals(other.descriptor); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.descriptor.hashCode(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceDescriptorImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceDescriptorImpl.java index 21f05c6..67d0be5 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceDescriptorImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceDescriptorImpl.java @@ -162,4 +162,30 @@ public final class UsbDeviceDescriptorImpl extends { return (byte) (this.descriptor.bNumConfigurations() & 0xff); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final UsbDeviceDescriptorImpl other = (UsbDeviceDescriptorImpl) o; + return this.descriptor.equals(other.descriptor); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.descriptor.hashCode(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceImpl.java index 26403a3..91a3787 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceImpl.java @@ -26,8 +26,10 @@ import javax.usb.UsbDevice; import javax.usb.UsbDeviceDescriptor; import javax.usb.UsbDisconnectedException; import javax.usb.UsbException; +import javax.usb.UsbHostManager; import javax.usb.UsbPort; import javax.usb.UsbStringDescriptor; +import javax.usb.event.UsbDeviceEvent; import javax.usb.event.UsbDeviceListener; import javax.usb.util.DefaultUsbControlIrp; @@ -64,6 +66,9 @@ public class UsbDeviceImpl implements UsbDevice /** The number of the currently active configuration. */ private final byte activeConfigurationNumber = 0; + /** The port this device is connected to. */ + private UsbPort port; + /** * Constructor. @@ -153,8 +158,57 @@ public class UsbDeviceImpl implements UsbDevice @Override public UsbPort getParentUsbPort() throws UsbDisconnectedException { - // TODO - throw new UnsupportedOperationException(); + if (this.port == null) throw new UsbDisconnectedException(); + return this.port; + } + + + /** + * Sets the parent USB port. If port is unset then a usbDeviceDetached event + * is send. + * + * @param port + * The port to set. Null to unset. + */ + + void setParentUsbPort(final UsbPort port) + { + if (this.port == null && port == null) + throw new IllegalStateException("Device already detached"); + if (this.port != null && port != null) + throw new IllegalStateException("Device already attached"); + + // Disconnect client devices + if (port == null && isUsbHub()) + { + final UsbPorts hub = (UsbPorts) this; + for (final UsbDevice device: hub.getAttachedUsbDevices()) + hub.disconnectUsbDevice(device); + } + + this.port = port; + + final UsbServicesImpl services; + try + { + services = (UsbServicesImpl) UsbHostManager.getUsbServices(); + } + catch (final UsbException e) + { + // Can't happen. When we got here then USB services are already + // loaded + throw new RuntimeException(e.toString(), e); + } + + if (port == null) + { + this.listeners.usbDeviceDetached(new UsbDeviceEvent(this)); + services.usbDeviceDetached(this); + } + else + { + services.usbDeviceAttached(this); + } } @@ -367,9 +421,11 @@ public class UsbDeviceImpl implements UsbDevice final int len = usb_get_descriptor(handle, USB_DT_STRING, 0, buffer); if (len < 0) throw new UsbException( - "Unable to get string descriptor languages: " + len); + "Unable to get string descriptor languages: " + + usb_strerror()); if (len < 2) - throw new UsbException("Illegal descriptor length: " + len); + throw new UsbException("Illegal descriptor length: " + + usb_strerror()); final short[] languages = new short[(len - 2) / 2]; if (languages.length == 0) return languages; buffer.position(2); @@ -418,8 +474,10 @@ public class UsbDeviceImpl implements UsbDevice public void syncSubmit(@SuppressWarnings("rawtypes") final List list) throws UsbException, IllegalArgumentException, UsbDisconnectedException { - // TODO - throw new UnsupportedOperationException(); + for (final Object item: list) + { + syncSubmit((UsbControlIrp) item); + } } @@ -431,8 +489,10 @@ public class UsbDeviceImpl implements UsbDevice public void asyncSubmit(@SuppressWarnings("rawtypes") final List list) throws UsbException, IllegalArgumentException, UsbDisconnectedException { - // TODO - throw new UnsupportedOperationException(); + for (final Object item: list) + { + asyncSubmit((UsbControlIrp) item); + } } @@ -468,4 +528,30 @@ public class UsbDeviceImpl implements UsbDevice { this.listeners.remove(listener); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object obj) + { + if (obj == null) return false; + if (obj == this) return true; + if (obj.getClass() != getClass()) return false; + final UsbDeviceImpl other = (UsbDeviceImpl) obj; + return this.device.equals(other.device); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.device.hashCode(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceScanner.java b/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceScanner.java index 360426c..296cf6a 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceScanner.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbDeviceScanner.java @@ -9,10 +9,15 @@ import static de.ailis.usb4java.USB.USB_CLASS_HUB; import static de.ailis.usb4java.USB.usb_find_busses; import static de.ailis.usb4java.USB.usb_find_devices; import static de.ailis.usb4java.USB.usb_get_busses; + +import java.util.ArrayList; +import java.util.List; + +import javax.usb.UsbDevice; + import de.ailis.usb4java.USBLock; import de.ailis.usb4java.USB_Bus; import de.ailis.usb4java.USB_Device; -import de.ailis.usb4java.USB_Device_Descriptor; /** @@ -26,18 +31,23 @@ class UsbDeviceScanner /** The virtual USB root hub. */ private final VirtualRootHub rootHub; + /** If scanner already scanned for devices. */ + private boolean scanned = false; + /** * Constructor. * + * @param services + * The USB services. * @param rootHub * The virtual USB root hub. */ - public UsbDeviceScanner(final VirtualRootHub rootHub) + public UsbDeviceScanner(final UsbServicesImpl services, + final VirtualRootHub rootHub) { this.rootHub = rootHub; - scan(); } @@ -45,7 +55,7 @@ class UsbDeviceScanner * Scans for USB device connection changes. */ - private void scan() + public void scan() { USBLock.acquire(); try @@ -55,15 +65,17 @@ class UsbDeviceScanner if (bussesChanged + devicesChanged == 0) return; USB_Bus bus = usb_get_busses(); + final List devices = new ArrayList(); while (bus != null) { final USB_Device device = bus.root_dev(); - if (device != null) - { - addDevice(this.rootHub, device); - } + if (device != null) devices.add(device); bus = bus.next(); } + updateHub(this.rootHub, devices.toArray(new USB_Device[devices + .size()])); + + this.scanned = true; } finally { @@ -73,29 +85,111 @@ class UsbDeviceScanner /** - * Adds the specified device to the specified hub and recursively scans for - * more devices. + * Creates a new JSR-80 USB Device from the specified low-level device. * - * @param parentHub - * The parent hub * @param device - * The device to add and scan. + * The low-level USB device + * @return A UsbDevice or UsbHub object depending on the device type. */ - private void addDevice(final UsbPorts parentHub, final USB_Device device) + private UsbDevice createUsbDevice(final USB_Device device) { - final USB_Device_Descriptor descriptor = device.descriptor(); - if (descriptor.bDeviceClass() == USB_CLASS_HUB) + if (device.descriptor().bDeviceClass() == USB_CLASS_HUB) { - final UsbHubImpl hub = new UsbHubImpl(device); - parentHub.connectUsbDevice(hub); - for (final USB_Device child : device.children()) - addDevice(hub, child); + return new UsbHubImpl(device); } else { - final UsbDeviceImpl dev = new UsbDeviceImpl(device); - parentHub.connectUsbDevice(dev); + return new UsbDeviceImpl(device); } } + + + /** + * Updates the specified hub ports with the specified devices. + * + * @param ports + * The hub ports to update. + * @param devices + * The detected devices. + */ + + private void updateHub(final UsbPorts ports, final USB_Device[] devices) + { + final List oldDevices = ports.getAttachedUsbDevices(); + final List newDevices = new ArrayList( + devices.length); + for (final USB_Device dev : devices) + { + if (dev == null) continue; + final UsbDevice device = createUsbDevice(dev); + newDevices.add(device); + + // Update existing devices + if (oldDevices.contains(device)) + { + if (device.isUsbHub()) + { + final UsbPorts hub = (UsbPorts) oldDevices.get(oldDevices + .indexOf(device)); + updateHub(hub, dev.children()); + } + } + + // Add new devices + else + { + ports.connectUsbDevice(device); + if (device.isUsbHub()) + updateHub((UsbPorts) device, dev.children()); + } + } + + // Disconnect old devices + for (final UsbDevice device : oldDevices) + { + if (!newDevices.contains(device)) + ports.disconnectUsbDevice(device); + } + } + + + /** + * Starts scanning in the background. + */ + + public void start() + { + final Thread thread = new Thread(new Runnable() + { + @Override + public void run() + { + while (true) + { + try + { + Thread.sleep(500); + } + catch (final InterruptedException e) + { + // Ignored + } + scan(); + } + } + }); + thread.setDaemon(true); + thread.start(); + } + + + /** + * Scans for devices but only if this was not already done. + */ + + public void firstScan() + { + if (!this.scanned) scan(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbEndpointDescriptorImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbEndpointDescriptorImpl.java index 4338f4e..5824e2d 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbEndpointDescriptorImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbEndpointDescriptorImpl.java @@ -75,4 +75,30 @@ public final class UsbEndpointDescriptorImpl extends { return (byte) (this.descriptor.bInterval() & 0xff); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final UsbEndpointDescriptorImpl other = (UsbEndpointDescriptorImpl) o; + return this.descriptor.equals(other.descriptor); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.descriptor.hashCode(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceDescriptorImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceDescriptorImpl.java index 509934c..ef3e48c 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceDescriptorImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceDescriptorImpl.java @@ -108,4 +108,30 @@ public final class UsbInterfaceDescriptorImpl extends { return (byte) (this.descriptor.iInterface() & 0xff); } + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final UsbInterfaceDescriptorImpl other = (UsbInterfaceDescriptorImpl) o; + return this.descriptor.equals(other.descriptor); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.descriptor.hashCode(); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbPortImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbPortImpl.java index 32eee22..6b0edb9 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbPortImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbPortImpl.java @@ -103,6 +103,7 @@ public final class UsbPortImpl implements UsbPort throw new IllegalStateException( "Port already has a connected device"); this.device = device; + ((UsbDeviceImpl) device).setParentUsbPort(this); } @@ -114,6 +115,8 @@ public final class UsbPortImpl implements UsbPort { if (this.device == null) throw new IllegalStateException("Port has no connected device"); + final UsbDeviceImpl device = (UsbDeviceImpl) this.device; this.device = null; + device.setParentUsbPort(null); } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbServicesImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbServicesImpl.java index 7c0c65a..2eabee1 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbServicesImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbServicesImpl.java @@ -7,9 +7,11 @@ package de.ailis.usb4java.jsr80; import static de.ailis.usb4java.USB.usb_init; +import javax.usb.UsbDevice; import javax.usb.UsbException; import javax.usb.UsbHub; import javax.usb.UsbServices; +import javax.usb.event.UsbServicesEvent; import javax.usb.event.UsbServicesListener; @@ -28,7 +30,7 @@ public final class UsbServicesImpl implements UsbServices private static final String IMP_VERSION = "0.1.12-1"; /** The API version. */ - private static final String API_VERSION = "1.0.2"; + private static final String API_VERSION = "1.0.1"; /** The USB services listeners. */ private final UsbServicesListenerList listeners = new UsbServicesListenerList(); @@ -48,7 +50,8 @@ public final class UsbServicesImpl implements UsbServices { usb_init(); this.rootHub = new VirtualRootHub(); - this.deviceScanner = new UsbDeviceScanner(this.rootHub); + this.deviceScanner = new UsbDeviceScanner(this, this.rootHub); + this.deviceScanner.start(); } @@ -59,6 +62,7 @@ public final class UsbServicesImpl implements UsbServices @Override public UsbHub getRootUsbHub() throws UsbException, SecurityException { + this.deviceScanner.firstScan(); return this.rootHub; } @@ -116,4 +120,28 @@ public final class UsbServicesImpl implements UsbServices { return IMP_DESCRIPTION; } + + + /** + * Informs listeners about a new attached device. + * + * @param device The new attached device. + */ + + void usbDeviceAttached(final UsbDevice device) + { + this.listeners.usbDeviceAttached(new UsbServicesEvent(this, device)); + } + + + /** + * Informs listeners about a detached device. + * + * @param device The detached device. + */ + + void usbDeviceDetached(final UsbDevice device) + { + this.listeners.usbDeviceDetached(new UsbServicesEvent(this, device)); + } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbServicesListenerList.java b/src/main/java/de/ailis/usb4java/jsr80/UsbServicesListenerList.java index 604600a..fa495bc 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbServicesListenerList.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbServicesListenerList.java @@ -50,6 +50,6 @@ public final class UsbServicesListenerList extends public final void usbDeviceDetached(final UsbServicesEvent event) { for (final UsbServicesListener listener : toArray()) - listener.usbDeviceAttached(event); + listener.usbDeviceDetached(event); } } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbStringDescriptorImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbStringDescriptorImpl.java index 67c4950..564cd1c 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbStringDescriptorImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbStringDescriptorImpl.java @@ -52,4 +52,31 @@ public final class UsbStringDescriptorImpl extends { return this.descriptor.toString(); } + + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + + @Override + public boolean equals(final Object o) + { + if (o == null) return false; + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final UsbStringDescriptorImpl other = (UsbStringDescriptorImpl) o; + return this.descriptor.equals(other.descriptor); + } + + + /** + * @see java.lang.Object#hashCode() + */ + + @Override + public int hashCode() + { + return this.descriptor.hashCode(); + } } diff --git a/src/test/java/Test.java b/src/test/java/Test.java deleted file mode 100644 index d23a3df..0000000 --- a/src/test/java/Test.java +++ /dev/null @@ -1,52 +0,0 @@ -import java.util.List; - -import javax.usb.UsbDevice; -import javax.usb.UsbHostManager; -import javax.usb.UsbHub; -import javax.usb.UsbPort; -import javax.usb.UsbServices; - -/* - * Copyright (C) 2011 Klaus Reimer - * See LICENSE.txt for licensing information. - */ - - -/** - * Test - * - * @author Klaus Reimer (k@ailis.de) - */ - -public class Test -{ - public static void dumpHub(final UsbHub rootHub, final String indent) throws Exception - { - final List ports = rootHub.getUsbPorts(); - for (final UsbPort port: ports) - { - System.out.print(indent); - System.out.format(" \\__%d: ", port.getPortNumber()); - if (port.isUsbDeviceAttached()) - { - final UsbDevice device = port.getUsbDevice(); - System.out.println(device.getProductString()); - if (device.isUsbHub()) - { - final UsbHub hub = (UsbHub) device; - dumpHub(hub, indent + " "); - } - } - else System.out.println("No device attached"); - } - } - - public static void main(final String[] args) throws Exception - { - final UsbServices services = UsbHostManager.getUsbServices(); - final UsbHub rootHub = services.getRootUsbHub(); - System.out.println(rootHub.getProductString()); - dumpHub(rootHub, ""); - } -} -