mirror of https://github.com/rusefi/usb4java.git
Finished pipe implementation.
This commit is contained in:
parent
cf4dd66d31
commit
8563bd97d5
|
@ -568,11 +568,21 @@ abstract class AbstractDevice implements UsbDevice
|
|||
@Override
|
||||
public final void syncSubmit(final UsbControlIrp irp) throws UsbException
|
||||
{
|
||||
if( (irp.bRequest() == UsbConst.REQUEST_SET_CONFIGURATION) && (irp.bmRequestType() ==0) )
|
||||
{
|
||||
final int result2 = usb_set_configuration(open(), irp.wValue());
|
||||
if (result2 < 0) throw new UsbException(usb_strerror());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
USBLock.acquire();
|
||||
try
|
||||
{
|
||||
final ByteBuffer buffer = ByteBuffer
|
||||
.allocateDirect(irp.getLength());
|
||||
buffer.put(irp.getData(), 0, irp.getLength());
|
||||
buffer.rewind();
|
||||
final USB_Dev_Handle handle = open();
|
||||
final int len = usb_control_msg(handle, irp.bmRequestType(),
|
||||
irp.bRequest(),
|
||||
|
@ -580,11 +590,13 @@ abstract class AbstractDevice implements UsbDevice
|
|||
if (len < 0) throw new UsbException(usb_strerror());
|
||||
buffer.rewind();
|
||||
buffer.get(irp.getData(), 0, len);
|
||||
irp.setActualLength(len);
|
||||
}
|
||||
finally
|
||||
{
|
||||
USBLock.release();
|
||||
}
|
||||
irp.complete();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
|
||||
* See LICENSE.txt for licensing information.
|
||||
*/
|
||||
|
||||
package de.ailis.usb4java.jsr80;
|
||||
|
||||
import static de.ailis.usb4java.USB.usb_strerror;
|
||||
|
||||
import javax.usb.UsbException;
|
||||
|
||||
|
||||
/**
|
||||
* libusb-specific UsbException.
|
||||
*
|
||||
* @author Klaus Reimer (k@ailis.de)
|
||||
*/
|
||||
|
||||
public class LibUsbException extends UsbException
|
||||
{
|
||||
/** Serial version UID. */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** The error code. */
|
||||
private final int errorCode;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param errorCode
|
||||
* The error code.
|
||||
*/
|
||||
|
||||
public LibUsbException(final int errorCode)
|
||||
{
|
||||
super(String.format("USB error %i: %s", errorCode, usb_strerror()));
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the error code.
|
||||
*
|
||||
* @return The error code
|
||||
*/
|
||||
|
||||
public int getErrorCode()
|
||||
{
|
||||
return this.errorCode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
|
||||
* See LICENSE.txt for licensing information.
|
||||
*/
|
||||
|
||||
package de.ailis.usb4java.jsr80;
|
||||
|
||||
import static de.ailis.usb4java.USB.usb_bulk_read;
|
||||
import static de.ailis.usb4java.USB.usb_bulk_write;
|
||||
import static de.ailis.usb4java.USB.usb_interrupt_read;
|
||||
import static de.ailis.usb4java.USB.usb_interrupt_write;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.usb.UsbConst;
|
||||
import javax.usb.UsbEndpoint;
|
||||
import javax.usb.UsbEndpointDescriptor;
|
||||
import javax.usb.UsbException;
|
||||
import javax.usb.UsbIrp;
|
||||
|
||||
import de.ailis.usb4java.USB_Dev_Handle;
|
||||
|
||||
|
||||
/**
|
||||
* This thread is responsible for processing the request packet queue of a pipe.
|
||||
* The thread is created and started when a pipe is opened and is stopped when
|
||||
* the pipe is closed.
|
||||
*
|
||||
* @author Klaus Reimer (k@ailis.de)
|
||||
*/
|
||||
|
||||
final class PipeQueueProcessor extends Thread
|
||||
{
|
||||
/** The pipe. */
|
||||
private final UsbPipeImpl pipe;
|
||||
|
||||
/** If thread should stop. */
|
||||
private boolean stop;
|
||||
|
||||
/** If thread is running or not. */
|
||||
private boolean running;
|
||||
|
||||
/** If packets are currently processed. */
|
||||
private boolean processing;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param pipe
|
||||
* The pipe.
|
||||
*/
|
||||
|
||||
public PipeQueueProcessor(final UsbPipeImpl pipe)
|
||||
{
|
||||
this.pipe = pipe;
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops the thread.
|
||||
*/
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
this.stop = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops the thread and waits until it has really stopped.
|
||||
*/
|
||||
|
||||
public void shutdownAndWait()
|
||||
{
|
||||
shutdown();
|
||||
while (isRunning())
|
||||
{
|
||||
try
|
||||
{
|
||||
wait();
|
||||
}
|
||||
catch (final InterruptedException e)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the USB endpoint descriptor.
|
||||
*
|
||||
* @return The USB endpoint descriptor.
|
||||
*/
|
||||
|
||||
private UsbEndpointDescriptor getEndpointDescriptor()
|
||||
{
|
||||
return this.pipe.getUsbEndpoint().getUsbEndpointDescriptor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the USB device.
|
||||
*
|
||||
* @return The USB device.
|
||||
*/
|
||||
|
||||
private AbstractDevice getDevice()
|
||||
{
|
||||
return this.pipe.getDevice();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes the specified request packet.
|
||||
*
|
||||
* @param irp
|
||||
* The request packet to process.
|
||||
*/
|
||||
|
||||
private void processIrp(final UsbIrp irp)
|
||||
{
|
||||
final UsbEndpoint endpoint = this.pipe.getUsbEndpoint();
|
||||
final byte type = endpoint.getType();
|
||||
final byte direction = endpoint.getDirection();
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case UsbConst.ENDPOINT_TYPE_BULK:
|
||||
switch (direction)
|
||||
{
|
||||
case UsbConst.ENDPOINT_DIRECTION_OUT:
|
||||
irp.setActualLength(bulkWrite(irp.getData()));
|
||||
break;
|
||||
|
||||
case UsbConst.ENDPOINT_DIRECTION_IN:
|
||||
irp.setActualLength(bulkRead(irp.getData()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UsbConst.ENDPOINT_TYPE_INTERRUPT:
|
||||
switch (direction)
|
||||
{
|
||||
case UsbConst.ENDPOINT_DIRECTION_OUT:
|
||||
irp.setActualLength(interruptWrite(irp.getData()));
|
||||
break;
|
||||
|
||||
case UsbConst.ENDPOINT_DIRECTION_IN:
|
||||
irp.setActualLength(interruptRead(irp.getData()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw new UsbException("Unsupported endpoint type: " + type);
|
||||
}
|
||||
catch (final UsbException e)
|
||||
{
|
||||
irp.setUsbException(e);
|
||||
}
|
||||
irp.complete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads bytes from a bulk endpoint into the specified data array.
|
||||
*
|
||||
* @param data
|
||||
* The data array to write the read bytes to.
|
||||
* @throws UsbException
|
||||
* When transfer fails.
|
||||
* @return The number of read bytes.
|
||||
*/
|
||||
|
||||
private int bulkRead(final byte[] data) throws UsbException
|
||||
{
|
||||
final UsbEndpointDescriptor descriptor = getEndpointDescriptor();
|
||||
final int size =
|
||||
Math.min(data.length, descriptor.wMaxPacketSize() & 0xffff);
|
||||
final int ep = descriptor.bEndpointAddress();
|
||||
final ByteBuffer buffer = ByteBuffer.allocateDirect(size);
|
||||
final int result = usb_bulk_read(getDevice().open(), ep, buffer, 5000);
|
||||
if (result < 0) throw new LibUsbException(result);
|
||||
buffer.rewind();
|
||||
buffer.get(data, 0, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified bytes to a bulk endpoint.
|
||||
*
|
||||
* @param data
|
||||
* The data array with the bytes to write.
|
||||
* @throws UsbException
|
||||
* When transfer fails.
|
||||
* @return The number of written bytes.
|
||||
*/
|
||||
|
||||
private int bulkWrite(final byte[] data) throws UsbException
|
||||
{
|
||||
final UsbEndpointDescriptor descriptor = getEndpointDescriptor();
|
||||
final int total = data.length;
|
||||
final int size = Math.min(total, descriptor.wMaxPacketSize() & 0xffff);
|
||||
final int ep = descriptor.bEndpointAddress();
|
||||
final ByteBuffer buffer = ByteBuffer.allocateDirect(size);
|
||||
final USB_Dev_Handle handle = getDevice().open();
|
||||
int written = 0;
|
||||
while (written < total)
|
||||
{
|
||||
buffer.put(data, written, Math.min(total - written, size));
|
||||
buffer.rewind();
|
||||
final int result = usb_bulk_write(handle, ep, buffer, 5000);
|
||||
if (result < 0) throw new LibUsbException(result);
|
||||
written += result;
|
||||
buffer.rewind();
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads bytes from an interrupt endpoint into the specified data array.
|
||||
*
|
||||
* @param data
|
||||
* The data array to write the read bytes to.
|
||||
* @throws UsbException
|
||||
* When transfer fails.
|
||||
* @return The number of read bytes.
|
||||
*/
|
||||
|
||||
private int interruptRead(final byte[] data) throws UsbException
|
||||
{
|
||||
final UsbEndpointDescriptor descriptor = getEndpointDescriptor();
|
||||
final int size =
|
||||
Math.min(data.length, descriptor.wMaxPacketSize() & 0xffff);
|
||||
final int ep = descriptor.bEndpointAddress();
|
||||
final ByteBuffer buffer = ByteBuffer.allocateDirect(size);
|
||||
final int result =
|
||||
usb_interrupt_read(getDevice().open(), ep, buffer, 5000);
|
||||
if (result < 0) throw new LibUsbException(result);
|
||||
buffer.rewind();
|
||||
buffer.get(data, 0, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the specified bytes to a interrupt endpoint.
|
||||
*
|
||||
* @param data
|
||||
* The data array with the bytes to write.
|
||||
* @throws UsbException
|
||||
* When transfer fails.
|
||||
* @return The number of written bytes.
|
||||
*/
|
||||
|
||||
private int interruptWrite(final byte[] data) throws UsbException
|
||||
{
|
||||
final UsbEndpointDescriptor descriptor = getEndpointDescriptor();
|
||||
final int total = data.length;
|
||||
final int size = Math.min(total, descriptor.wMaxPacketSize() & 0xffff);
|
||||
final int ep = descriptor.bEndpointAddress();
|
||||
final ByteBuffer buffer = ByteBuffer.allocateDirect(size);
|
||||
final USB_Dev_Handle handle = getDevice().open();
|
||||
int written = 0;
|
||||
while (written < total)
|
||||
{
|
||||
buffer.put(data, written, Math.min(total - written, size));
|
||||
buffer.rewind();
|
||||
final int result = usb_interrupt_write(handle, ep, buffer, 5000);
|
||||
if (result < 0) throw new LibUsbException(result);
|
||||
written += result;
|
||||
buffer.rewind();
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
this.running = true;
|
||||
final UsbIrpQueue queue = this.pipe.getQueue();
|
||||
while (!this.stop)
|
||||
{
|
||||
UsbIrp irp = queue.get();
|
||||
while (!this.stop && irp != null)
|
||||
{
|
||||
this.processing = true;
|
||||
processIrp(irp);
|
||||
irp = queue.get();
|
||||
}
|
||||
this.processing = false;
|
||||
try
|
||||
{
|
||||
wait();
|
||||
}
|
||||
catch (final InterruptedException e)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
this.running = false;
|
||||
notify();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if this thread is running.
|
||||
*
|
||||
* @return True if thread is running, false if not.
|
||||
*/
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return this.running;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if packets are currently processed.
|
||||
*
|
||||
* @return If packets are processed.
|
||||
*/
|
||||
|
||||
public boolean isProcessing()
|
||||
{
|
||||
return this.processing;
|
||||
}
|
||||
}
|
|
@ -84,7 +84,7 @@ public final class UsbConfigurationImpl implements UsbConfiguration
|
|||
this.interfaces.put(ifaceNumber, settings);
|
||||
}
|
||||
final UsbInterface usbInterface = new UsbInterfaceImpl(this,
|
||||
desc);
|
||||
desc, device);
|
||||
|
||||
// If we have no active setting for current interface number
|
||||
// yet or the alternate setting number is 0 (which marks the
|
||||
|
@ -92,7 +92,10 @@ public final class UsbConfigurationImpl implements UsbConfiguration
|
|||
// the active setting.
|
||||
if (!this.activeSettings.containsKey(ifaceNumber) ||
|
||||
desc.bAlternateSetting() == 0)
|
||||
{
|
||||
this.activeSettings.put(ifaceNumber, usbInterface);
|
||||
System.out.println("Active: " + usbInterface);
|
||||
}
|
||||
|
||||
// Add the interface to the settings list
|
||||
settings.put(settingNumber, usbInterface);
|
||||
|
@ -160,7 +163,7 @@ public final class UsbConfigurationImpl implements UsbConfiguration
|
|||
@Override
|
||||
public UsbInterface getUsbInterface(final byte number)
|
||||
{
|
||||
return this.activeSettings.get(number);
|
||||
return this.activeSettings.get((int) number);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
|
||||
* See LICENSE.txt for licensing information.
|
||||
*/
|
||||
|
||||
package de.ailis.usb4java.jsr80;
|
||||
|
||||
import javax.usb.UsbConst;
|
||||
import javax.usb.UsbEndpoint;
|
||||
import javax.usb.UsbEndpointDescriptor;
|
||||
import javax.usb.UsbInterface;
|
||||
import javax.usb.UsbPipe;
|
||||
|
||||
|
||||
/**
|
||||
* usb4java implementation of UsbEndpoint.
|
||||
*
|
||||
* @author Klaus Reimer (k@ailis.de)
|
||||
*/
|
||||
|
||||
public final class UsbEndpointImpl implements UsbEndpoint
|
||||
{
|
||||
/** The USB interface this endpoint belongs to. */
|
||||
private final UsbInterfaceImpl iface;
|
||||
|
||||
/** The USB endpoint descriptor. */
|
||||
private final UsbEndpointDescriptor descriptor;
|
||||
|
||||
/** The USB pipe for this endpoint. */
|
||||
private final UsbPipe pipe;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param iface
|
||||
* The USB interface this endpoint belongs to.
|
||||
* @param descriptor
|
||||
* The USB endpoint descriptor.
|
||||
* @param device
|
||||
* The USB device.
|
||||
*/
|
||||
|
||||
public UsbEndpointImpl(final UsbInterfaceImpl iface,
|
||||
final UsbEndpointDescriptor descriptor, final AbstractDevice device)
|
||||
{
|
||||
this.iface = iface;
|
||||
this.descriptor = descriptor;
|
||||
this.pipe = new UsbPipeImpl(this, device);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see UsbEndpoint#getUsbInterface()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbInterface getUsbInterface()
|
||||
{
|
||||
return this.iface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see UsbEndpoint#getUsbEndpointDescriptor()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbEndpointDescriptor getUsbEndpointDescriptor()
|
||||
{
|
||||
return this.descriptor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see UsbEndpoint#getDirection()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public byte getDirection()
|
||||
{
|
||||
return (byte) (this.descriptor.bEndpointAddress() & UsbConst.ENDPOINT_DIRECTION_MASK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see UsbEndpoint#getType()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public byte getType()
|
||||
{
|
||||
return (byte) (this.descriptor.bmAttributes() & UsbConst.ENDPOINT_TYPE_MASK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see UsbEndpoint#getUsbPipe()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbPipe getUsbPipe()
|
||||
{
|
||||
return this.pipe;
|
||||
}
|
||||
}
|
|
@ -8,11 +8,14 @@ package de.ailis.usb4java.jsr80;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.usb.UsbClaimException;
|
||||
import javax.usb.UsbConfiguration;
|
||||
import javax.usb.UsbEndpoint;
|
||||
import javax.usb.UsbEndpointDescriptor;
|
||||
import javax.usb.UsbException;
|
||||
import javax.usb.UsbInterface;
|
||||
import javax.usb.UsbInterfaceDescriptor;
|
||||
|
@ -20,6 +23,7 @@ import javax.usb.UsbInterfacePolicy;
|
|||
import javax.usb.UsbNotActiveException;
|
||||
|
||||
import de.ailis.usb4java.USBLock;
|
||||
import de.ailis.usb4java.USB_Endpoint_Descriptor;
|
||||
import de.ailis.usb4java.USB_Interface_Descriptor;
|
||||
|
||||
|
||||
|
@ -37,6 +41,13 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
/** The interface descriptor. */
|
||||
private final UsbInterfaceDescriptor descriptor;
|
||||
|
||||
/** The endpoint address to endpoints mapping. */
|
||||
private final Map<Byte, UsbEndpoint> endpointMap =
|
||||
new HashMap<Byte, UsbEndpoint>();
|
||||
|
||||
/** The endpoints. */
|
||||
private final List<UsbEndpoint> endpoints;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -45,15 +56,30 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
* The USB configuration.
|
||||
* @param lowLevelDescriptor
|
||||
* The low-level USB interface descriptor.
|
||||
* @param device
|
||||
* The USB device.
|
||||
*/
|
||||
|
||||
public UsbInterfaceImpl(final UsbConfigurationImpl configuration,
|
||||
final USB_Interface_Descriptor lowLevelDescriptor)
|
||||
final USB_Interface_Descriptor lowLevelDescriptor,
|
||||
final AbstractDevice device)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.descriptor = new UsbInterfaceDescriptorImpl(lowLevelDescriptor);
|
||||
}
|
||||
|
||||
final List<UsbEndpoint> endpoints = new ArrayList<UsbEndpoint>();
|
||||
for (final USB_Endpoint_Descriptor desc : lowLevelDescriptor
|
||||
.endpoint())
|
||||
{
|
||||
final UsbEndpointDescriptor descriptor =
|
||||
new UsbEndpointDescriptorImpl(desc);
|
||||
final UsbEndpoint endpoint =
|
||||
new UsbEndpointImpl(this, descriptor, device);
|
||||
this.endpointMap.put(descriptor.bEndpointAddress(), endpoint);
|
||||
endpoints.add(endpoint);
|
||||
}
|
||||
this.endpoints = Collections.unmodifiableList(endpoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the configuration is active. If not then an
|
||||
|
@ -108,7 +134,8 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
device.setActiveUsbConfigurationNumber(this.configuration
|
||||
.getUsbConfigurationDescriptor().bConfigurationValue());
|
||||
device.claimInterface(this.descriptor.bInterfaceNumber());
|
||||
this.configuration.setUsbInterface(this.descriptor.bInterfaceNumber(), this);
|
||||
this.configuration.setUsbInterface(
|
||||
this.descriptor.bInterfaceNumber(), this);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -148,6 +175,9 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
System.out.println(this.configuration.getUsbInterface(this.descriptor
|
||||
.bInterfaceNumber()));
|
||||
System.out.println(this);
|
||||
return this.configuration.getUsbInterface(this.descriptor
|
||||
.bInterfaceNumber()) == this;
|
||||
}
|
||||
|
@ -238,8 +268,7 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
@Override
|
||||
public List<UsbEndpoint> getUsbEndpoints()
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
return this.endpoints;
|
||||
}
|
||||
|
||||
|
||||
|
@ -250,8 +279,7 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
@Override
|
||||
public UsbEndpoint getUsbEndpoint(final byte address)
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
return this.endpointMap.get(address);
|
||||
}
|
||||
|
||||
|
||||
|
@ -262,8 +290,7 @@ public final class UsbInterfaceImpl implements UsbInterface
|
|||
@Override
|
||||
public boolean containsUsbEndpoint(final byte address)
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
return this.endpointMap.containsKey(address);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
|
||||
* See LICENSE.txt for licensing information.
|
||||
*/
|
||||
|
||||
package de.ailis.usb4java.jsr80;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.usb.UsbIrp;
|
||||
|
||||
|
||||
/**
|
||||
* USB I/O request packet queue.
|
||||
*
|
||||
* @author Klaus Reimer (k@ailis.de)
|
||||
*/
|
||||
|
||||
final class UsbIrpQueue
|
||||
{
|
||||
/** The queued packets. */
|
||||
private final Deque<UsbIrp> irps = new LinkedList<UsbIrp>();
|
||||
|
||||
|
||||
/**
|
||||
* Adds a request packet to the queue.
|
||||
*
|
||||
* @param irp
|
||||
* The packet to add to the queue.
|
||||
*/
|
||||
|
||||
public void add(final UsbIrp irp)
|
||||
{
|
||||
synchronized (this.irps)
|
||||
{
|
||||
this.irps.add(irp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next request packet to process.
|
||||
*
|
||||
* @return The next packet to process or null if queue is empty.
|
||||
*/
|
||||
|
||||
public UsbIrp get()
|
||||
{
|
||||
synchronized (this.irps)
|
||||
{
|
||||
return this.irps.poll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes all remaining unprocessed requests.
|
||||
*/
|
||||
|
||||
public void clear()
|
||||
{
|
||||
synchronized (this.irps)
|
||||
{
|
||||
this.irps.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if queue is empty.
|
||||
*
|
||||
* @return True if queue is empty, false if not.
|
||||
*/
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return this.irps.isEmpty();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
|
||||
* See LICENSE.txt for licensing information.
|
||||
*/
|
||||
|
||||
package de.ailis.usb4java.jsr80;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.usb.UsbConfiguration;
|
||||
import javax.usb.UsbControlIrp;
|
||||
import javax.usb.UsbDisconnectedException;
|
||||
import javax.usb.UsbException;
|
||||
import javax.usb.UsbInterface;
|
||||
import javax.usb.UsbIrp;
|
||||
import javax.usb.UsbNotActiveException;
|
||||
import javax.usb.UsbNotClaimedException;
|
||||
import javax.usb.UsbNotOpenException;
|
||||
import javax.usb.UsbPipe;
|
||||
import javax.usb.event.UsbPipeListener;
|
||||
import javax.usb.util.DefaultUsbControlIrp;
|
||||
import javax.usb.util.DefaultUsbIrp;
|
||||
|
||||
|
||||
/**
|
||||
* usb4java implementation of UsbPipe.
|
||||
*
|
||||
* @author Klaus Reimer (k@ailis.de)
|
||||
*/
|
||||
|
||||
public final class UsbPipeImpl implements UsbPipe
|
||||
{
|
||||
/** The endpoint this pipe belongs to. */
|
||||
private final UsbEndpointImpl endpoint;
|
||||
|
||||
/** The device. */
|
||||
private final AbstractDevice device;
|
||||
|
||||
/** The USB pipe listeners. */
|
||||
private final UsbPipeListenerList listeners = new UsbPipeListenerList();
|
||||
|
||||
/** If pipe is open or not. */
|
||||
private boolean opened;
|
||||
|
||||
/** The request queue. */
|
||||
private final UsbIrpQueue queue = new UsbIrpQueue();
|
||||
|
||||
/** The thread which processes the queue. null if none. */
|
||||
private PipeQueueProcessor queueProcessor;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param endpoint
|
||||
* The endpoint this pipe belongs to.
|
||||
* @param device
|
||||
* The USB device.
|
||||
*/
|
||||
|
||||
|
||||
UsbPipeImpl(final UsbEndpointImpl endpoint, final AbstractDevice device)
|
||||
{
|
||||
this.endpoint = endpoint;
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the USB device.
|
||||
*
|
||||
* @return The USB device.
|
||||
*/
|
||||
|
||||
AbstractDevice getDevice()
|
||||
{
|
||||
return this.device;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures the pipe is active.
|
||||
*
|
||||
* @throws UsbNotActiveException
|
||||
* When pipe is not active
|
||||
*/
|
||||
|
||||
private void checkActive() throws UsbNotActiveException
|
||||
{
|
||||
if (!isActive())
|
||||
throw new UsbNotActiveException("Pipe is not active.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures the interface is active.
|
||||
*
|
||||
* @throws UsbNotClaimedException
|
||||
* When interface is not claimed.
|
||||
*/
|
||||
|
||||
private void checkClaimed() throws UsbNotClaimedException
|
||||
{
|
||||
if (!this.endpoint.getUsbInterface().isClaimed())
|
||||
throw new UsbNotClaimedException("Interface is not claimed.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures the device is not disconnected.
|
||||
*
|
||||
* @throws UsbDisconnectedException
|
||||
* When device has been disconnected.
|
||||
*/
|
||||
|
||||
private void checkDisconnected() throws UsbDisconnectedException
|
||||
{
|
||||
// TODO implement me
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures the pipe is open.
|
||||
*
|
||||
* @throws UsbNotOpenException
|
||||
* When pipe is not open.
|
||||
*/
|
||||
|
||||
private void checkOpen() throws UsbNotOpenException
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new UsbNotOpenException("Pipe is not open.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#open()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void open() throws UsbException, UsbNotActiveException,
|
||||
UsbNotClaimedException, UsbDisconnectedException
|
||||
{
|
||||
checkActive();
|
||||
checkClaimed();
|
||||
checkDisconnected();
|
||||
if (this.opened) throw new UsbException("Pipe is already open");
|
||||
|
||||
this.queueProcessor = new PipeQueueProcessor(this);
|
||||
this.queueProcessor.start();
|
||||
|
||||
this.opened = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#close()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void close() throws UsbException, UsbNotActiveException,
|
||||
UsbNotOpenException, UsbDisconnectedException
|
||||
{
|
||||
checkActive();
|
||||
checkClaimed();
|
||||
checkDisconnected();
|
||||
if (!this.opened) throw new UsbException("Pipe is already closed");
|
||||
if (this.queueProcessor.isProcessing() || !this.queue.isEmpty())
|
||||
throw new UsbException("Pipe is still in use");
|
||||
|
||||
this.queue.clear();
|
||||
this.queueProcessor.shutdownAndWait();
|
||||
this.queueProcessor = null;
|
||||
|
||||
this.opened = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#isActive()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
final UsbInterface iface = this.endpoint.getUsbInterface();
|
||||
final UsbConfiguration config = iface.getUsbConfiguration();
|
||||
return iface.isActive() && config.isActive();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#isOpen()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return this.opened;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#getUsbEndpoint()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbEndpointImpl getUsbEndpoint()
|
||||
{
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#syncSubmit(byte[])
|
||||
*/
|
||||
|
||||
@Override
|
||||
public int syncSubmit(final byte[] data) throws UsbException,
|
||||
UsbNotActiveException, UsbNotOpenException, IllegalArgumentException,
|
||||
UsbDisconnectedException
|
||||
{
|
||||
final UsbIrp irp = asyncSubmit(data);
|
||||
irp.waitUntilComplete();
|
||||
if (irp.isUsbException()) throw irp.getUsbException();
|
||||
return irp.getActualLength();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#asyncSubmit(byte[])
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbIrp asyncSubmit(final byte[] data) throws UsbException,
|
||||
UsbNotActiveException, UsbNotOpenException, IllegalArgumentException,
|
||||
UsbDisconnectedException
|
||||
{
|
||||
if (data == null)
|
||||
throw new IllegalArgumentException("data must not be null");
|
||||
final UsbIrp irp = createUsbIrp();
|
||||
irp.setAcceptShortPacket(true);
|
||||
irp.setData(data);
|
||||
asyncSubmit(irp);
|
||||
return irp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#syncSubmit(javax.usb.UsbIrp)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void syncSubmit(final UsbIrp irp) throws UsbException,
|
||||
UsbNotActiveException, UsbNotOpenException, IllegalArgumentException,
|
||||
UsbDisconnectedException
|
||||
{
|
||||
if (irp == null)
|
||||
throw new IllegalArgumentException("irp must not be null");
|
||||
asyncSubmit(irp);
|
||||
irp.waitUntilComplete();
|
||||
if (irp.isUsbException()) throw irp.getUsbException();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#asyncSubmit(javax.usb.UsbIrp)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void asyncSubmit(final UsbIrp irp) throws UsbException,
|
||||
UsbNotActiveException, UsbNotOpenException, IllegalArgumentException,
|
||||
UsbDisconnectedException
|
||||
{
|
||||
if (irp == null)
|
||||
throw new IllegalArgumentException("irp must not be null");
|
||||
checkActive();
|
||||
checkDisconnected();
|
||||
checkOpen();
|
||||
|
||||
this.queue.add(irp);
|
||||
this.queueProcessor.notify();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#syncSubmit(java.util.List)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void syncSubmit(@SuppressWarnings("rawtypes") final List list)
|
||||
throws UsbException, UsbNotActiveException, UsbNotOpenException,
|
||||
IllegalArgumentException, UsbDisconnectedException
|
||||
{
|
||||
for (final Object item: list)
|
||||
{
|
||||
final UsbIrp irp = (UsbIrp) item;
|
||||
syncSubmit(irp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#asyncSubmit(java.util.List)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void asyncSubmit(@SuppressWarnings("rawtypes") final List list)
|
||||
throws UsbException, UsbNotActiveException, UsbNotOpenException,
|
||||
IllegalArgumentException, UsbDisconnectedException
|
||||
{
|
||||
for (final Object item: list)
|
||||
{
|
||||
final UsbIrp irp = (UsbIrp) item;
|
||||
asyncSubmit(irp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#abortAllSubmissions()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void abortAllSubmissions() throws UsbNotActiveException,
|
||||
UsbNotOpenException, UsbDisconnectedException
|
||||
{
|
||||
checkActive();
|
||||
checkDisconnected();
|
||||
checkOpen();
|
||||
this.queue.clear();
|
||||
this.queueProcessor.shutdownAndWait();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#createUsbIrp()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbIrp createUsbIrp()
|
||||
{
|
||||
return new DefaultUsbIrp();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#createUsbControlIrp(byte, byte, short, short)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public UsbControlIrp createUsbControlIrp(final byte bmRequestType,
|
||||
final byte bRequest,
|
||||
final short wValue, final short wIndex)
|
||||
{
|
||||
return new DefaultUsbControlIrp(bmRequestType, bRequest, wValue, wIndex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#addUsbPipeListener(javax.usb.event.UsbPipeListener)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void addUsbPipeListener(final UsbPipeListener listener)
|
||||
{
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.usb.UsbPipe#removeUsbPipeListener(javax.usb.event.UsbPipeListener)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void removeUsbPipeListener(final UsbPipeListener listener)
|
||||
{
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the request packet queue.
|
||||
*
|
||||
* @return The request packet queue. Never null.
|
||||
*/
|
||||
|
||||
UsbIrpQueue getQueue()
|
||||
{
|
||||
return this.queue;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue