From 5925b7ce1bccbc933e1cab70a635ee085a91c16d Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Sun, 24 Feb 2013 21:59:59 +0100 Subject: [PATCH] Add control IO tests --- .../java/javax/usb/tck/ControlIOTest.java | 1655 +++++++++++++++++ .../javax/usb/tck/FindControlIODevice.java | 330 ++++ 2 files changed, 1985 insertions(+) create mode 100755 src/test/java/javax/usb/tck/ControlIOTest.java create mode 100755 src/test/java/javax/usb/tck/FindControlIODevice.java diff --git a/src/test/java/javax/usb/tck/ControlIOTest.java b/src/test/java/javax/usb/tck/ControlIOTest.java new file mode 100755 index 0000000..4104d2c --- /dev/null +++ b/src/test/java/javax/usb/tck/ControlIOTest.java @@ -0,0 +1,1655 @@ +package javax.usb.tck; + +/** + * Copyright (c) 2004, International Business Machines Corporation. + * All Rights Reserved. + * + * This software is provided and licensed under the terms and conditions + * of the Common Public License: + * http://oss.software.ibm.com/developerworks/opensource/license-cpl.html + */ + +/* + * Change Activity: See below. + * + * FLAG REASON RELEASE DATE WHO DESCRIPTION + * ---- -------- -------- ------ ------- ------------------------------------ + * 0000 nnnnnnn yymmdd Initial Development + * $P1 tck.rel1 040804 raulortz Support for UsbDisconnectedException + * $P2 tck.rel1 040916 raulortz Redesign TCK to create base and optional + * tests. Separate setConfig, setInterface + * and isochronous transfers as optionals. + */ + +import java.util.*; + +import junit.framework.*; + +import javax.usb.*; +import javax.usb.util.*; +import javax.usb.event.*; + +import org.junit.runner.RunWith; + +import de.ailis.usb4java.TCKRunner; + +/** + * Control I/O Test - Synchronous and asynchronous Control Irp and Control + * Irp List submissions + *

+ * This test verifies pipes can be opened on a control endpoint other than + * endpoint 0. The programmable device used in this test suite supports + * only one control pipe, the default control pipe. The target device for + * this test will be the device with at least one non default control pipe + * as specified in the hardware configurations. Because the target device + * is not programmable, minimal communication verification will be performed + * with the non default control pipe endpoint. + * @author Joshua Lowry + */ + +@SuppressWarnings("all") +@RunWith(TCKRunner.class) +public class ControlIOTest extends TestCase +{ + + public ControlIOTest(String name) + { + super(name); + } + + /** + * The setUp method reinitializes the private variables between test cases, + * so no run will affect the next run. + * @throws Exception + */ + protected void setUp() throws Exception { + usbCtrlIODev = null; + usbCtrlIOInterface = null; + usbCtrlIOInterfaceDesc = null; + usbCtrlIOEndpoint = null; + usbCtrlIOEndpointDesc = null; + usbCtrlIOPipe = null; + numDataEvents = 0; + numErrorEvents = 0; + LastUsbPipeDataEvent = new ArrayList(); + LastUsbPipeErrorEvent = new ArrayList(); + } + + /** + * The tearDown method closes the the UsbPipe if it is left open and + * releases the UsbInterface if it is left claimed after a test, so a + * failing test case doesn't prevent the next test case from running. + * @throws Exception + */ + protected void tearDown() throws Exception { + LastUsbPipeDataEvent.clear(); + LastUsbPipeErrorEvent.clear(); + try + { + if ( usbCtrlIOPipe.isOpen() ) + { + usbCtrlIOPipe.abortAllSubmissions(); + usbCtrlIOPipe.close(); + } + } catch ( UsbNotOpenException uNOE ) + { + fail("ControlIO Pipe reports is opened but throws UsbNotOpenException when " + + "close or abortAllSubmissions method called: " + uNOE.getMessage()); + } catch ( UsbNotActiveException uNAE ) { + fail("ControlIO Pipe reports is opened but throws UsbNotActiveExceptio when " + + "close or abortAllSubmissions method called: " + uNAE.getMessage()); + } catch ( UsbDisconnectedException uDE ) { + fail("ControlIO Pipe reports is opened but throws UsbDisconnectedException when " + + "close or abortAllSubmissions method called: " + uDE.getMessage()); + } catch ( UsbException uE ) { + fail("The close method was unable to close the ControlIO Pipe: " + uE.getMessage()); + } + try + { + if ( usbCtrlIOInterface.isClaimed() ) + usbCtrlIOInterface.release(); + } catch ( UsbClaimException uCE ) + { + fail("UsbInterface reports interface is claimed, release method throws" + + "UsbClaimException (device not claimed): " + uCE.getMessage()); + } catch ( UsbException uE ) + { + fail("release method unable to release UsbInterface: " + uE.getMessage()); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + } + + /** + * Finds the first USB device with a UsbEndpoint with the + * ENDPOINT_TYPE_CONTROL type other than Endpoint 0. If it finds such a + * device, this method ensures that the control UsbEndpoint's interface is + * the active UsbInterface, claims that UsbInterface and opens its UsbPipe, + * as well as asserting that alll the methods relating to the open succeed. + * If it doesn't find such a UsbEndpoint, the method fails. + * @throws Exception + */ + protected void openControlIOPipe() throws Exception { + short wMaxPacketSize; + + usbCtrlIODev = new FindControlIODevice().getControlIODevice(); + assertNotNull("There is no device with a control pipe other than the default connected", + usbCtrlIODev); + + usbCtrlIOEndpoint = FindControlIODevice.getControlIOEndpoint(usbCtrlIODev); + usbCtrlIOEndpointDesc = usbCtrlIOEndpoint.getUsbEndpointDescriptor(); + assertNotNull("There is no endpoint other than Endpoint0 that is the control type", + usbCtrlIOEndpoint); + assertTrue("This endpoint should not be endpoint0", + usbCtrlIOEndpointDesc.bEndpointAddress() != (byte) 0x00); + assertEquals("The endpoint type is not Control", + UsbConst.ENDPOINT_TYPE_CONTROL, usbCtrlIOEndpoint.getType()); + + usbCtrlIOInterface = usbCtrlIOEndpoint.getUsbInterface(); + usbCtrlIOInterfaceDesc = usbCtrlIOInterface.getUsbInterfaceDescriptor(); + + // @P2D23 + UsbConfiguration usbCtrlIOConfig; + UsbConfigurationDescriptor usbCtrlIOConfigDesc; + + usbCtrlIOConfig = usbCtrlIOInterface.getUsbConfiguration(); + usbCtrlIOConfigDesc = usbCtrlIOConfig.getUsbConfigurationDescriptor(); + + assertTrue("The configuration, interface & alternate setting for the Control Enpoint isn't active", + usbCtrlIOInterface.isActive()); + // @P2D2 + + try + { + usbCtrlIOInterface.claim(); + } catch ( UsbNotActiveException uNAE ) + { + fail("The interface should be active when claim is called"); + } catch ( UsbClaimException uCE ) + { + fail("The interface should not be claimed when claim is called"); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } catch ( UsbException uE ) // @P1C + { + fail("The interface was unable to be claimed"); + } + + assertTrue("The current interface w/the control endpoint is not claimed after claim is called", + usbCtrlIOInterface.isClaimed()); + usbCtrlIOPipe = usbCtrlIOEndpoint.getUsbPipe(); + assertTrue("The Control I/O Pipe is not active!", usbCtrlIOPipe.isActive()); + usbCtrlIOPipe.addUsbPipeListener(usbCtrlIOPipeListener); + assertFalse("The Control I/O Pipe should not be open before open is called", + usbCtrlIOPipe.isOpen()); + + try + { + usbCtrlIOPipe.open(); + } catch ( UsbNotActiveException uNAE ) + { + fail("The pipe's configuration and interface should be active when open is called"); + } catch ( UsbNotClaimedException uNCE ) + { + fail("The pipe's interface should be claimed when open is called"); + } catch ( UsbException uE ) + { + fail("The interface was unable to be opened"); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + assertTrue("The Control I/O Pipe should be open after open is called", + usbCtrlIOPipe.isOpen()); + assertNotNull("No Endpoint Descriptor was returned while attempting to open the Control I/O Pipe", + usbCtrlIOEndpointDesc); + assertNotNull("The Control Pipe was not opened", + usbCtrlIOPipe); + + wMaxPacketSize = usbCtrlIOEndpointDesc.wMaxPacketSize(); + switch ( wMaxPacketSize ) + { + case 8: + case 16: + case 32: + case 64: + break; + default: + fail("The max packet size does not conform to a valid max packet size for control pipes"); + break; + } + + } + + /** + * Closes the UsbPipe and releases the UsbInterface for the UsbEndpoint + * found in the openControlIOPipe() method. It also tests everything + * related to closing the UsbPipe and releasing the UsbInterface. + * @throws Exception + */ + protected void closeControlIOPipe() throws Exception { + assertTrue("UsbPipe.isOpen() should be true before UsbPipe.close() is called", + usbCtrlIOPipe.isOpen()); + + try + { + usbCtrlIOPipe.close(); + } catch ( UsbException uE ) + { + fail("The Control I/O Pipe couldn't be closed"); + } catch ( UsbNotOpenException uNOE ) + { + fail("The Control I/O Pipe threw a UsbNotOpenException on closing an open pipe"); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + assertFalse("UsbPipe.isOpen() should be false after UsbPipe.close() is called", + usbCtrlIOPipe.isOpen()); + usbCtrlIOPipe.removeUsbPipeListener(usbCtrlIOPipeListener); + assertTrue("The Control I/O Interface should be claimed before UsbInterface.release() is called", + usbCtrlIOInterface.isClaimed()); + + try + { + usbCtrlIOInterface.release(); + } catch ( UsbClaimException uCE ) + { + fail("A claimed interface shouldn't throw the UsbClaimException"); + } catch ( UsbException uE ) + { + fail("The interface could not be released."); + } catch ( UsbNotActiveException uNAE ) + { + fail("An active interface setting shouldn't throw the UsbNotActiveException"); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + assertFalse("The Control I/O Interface shouldn't be claimed after UsbInterface.release() is called", + usbCtrlIOInterface.isClaimed()); + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a UsbControlIrp OUT to the device. It submits the + * UsbControlIrp ten times, and checks that it got either a UsbPipeDataEvent + * or a UsbPipeErrorEvent back. If it gets a data event back, it compares + * the Irp in the data event to the Irp submitted and checks that the + * buffered data did not change, and if it gets an error event back, it + * makes sure that the exception in the event is not null. It also checks + * that the UsbControlIrp is complete immediately after the syncSubmit + * returns. + * @throws Exception + */ + public void testControlIOSyncSubmitIrp_OUT() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_OUT | + UsbConst.REQUESTTYPE_RECIPIENT_ENDPOINT; + byte bRequest = UsbConst.REQUEST_CLEAR_FEATURE; + short wValue = (short) 0x0000; + short wIndex = usbCtrlIOEndpointDesc.bEndpointAddress(); + byte buffer[] = new byte[0]; + int usbCtrlIOIrpOffset; + int usbCtrlIOIrpLength; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer); + usbCtrlIOIrpOffset = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength = usbCtrlIOIrp.getLength(); + + assertFalse("OUT Irp #" + (i+1) + ": UsbCotrolIrp should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + + try + { + usbCtrlIOPipe.syncSubmit(usbCtrlIOIrp); + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for OUT syncSubmit #" + (i+1)); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for OUT syncSubmit #" + (i+1)); + } catch ( UsbException uE ) + { + assertNotNull("The OUT syncSubmit UsbException should not be null", + uE); + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + assertEquals("The UsbException for the Irp should match the exception caught", + usbCtrlIOIrp.getUsbException(), uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + if ( !usbCtrlIOIrp.isComplete() ) + { + fail("OUT Irp #" + (i+1) + ": The UsbControlIrp is not complete after syncSubmit"); + } + + for ( int j = 0; j < 400; j++ ) + { + Thread.sleep(5); + if ( numDataEvents + numErrorEvents > i ) + { + break; + } + } + if ( numDataEvents + numErrorEvents <= i ) + { + fail("No UsbPipeDataEvent or UsbPipeErrorEvent received"); + } + + assertEquals("The OUT UsbControlIrp data should not be altered", + buffer, usbCtrlIOIrp.getData()); + assertEquals("The OUT bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The OUT bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The OUT getOffset() shouldn't be altered", + usbCtrlIOIrpOffset, usbCtrlIOIrp.getOffset()); + assertEquals("The OUT getLength() shouldn't be altered", + usbCtrlIOIrpLength, usbCtrlIOIrp.getLength()); + + if ( !usbCtrlIOIrp.isUsbException() ) + { + UsbPipeDataEvent lastUsbPipeDE = + (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + // TODO No idea why these two arrays should match. Ignoring for now + //assertEquals("The OUT data event getData doesn't match the OUT Irp getData", + // usbCtrlIOIrp.getData(), lastUsbPipeDE.getData()); + assertEquals("The OUT data event UsbIrp ActualLength doesn't match the OUT Irp ActualLenth", + usbCtrlIOIrp.getActualLength(), lastUsbPipeDE.getUsbIrp().getActualLength()); + assertEquals("The OUT data event UsbIrp getOffset doesn't match the OUT Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The OUT data event UsbIrp getLength doesn't match the OUT Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The OUT data event UsbPipe doesn't match the one the Irp was submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The OUT error event's UsbPipe doesn't match the one the Irp was submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + if ( numDataEvents + numErrorEvents > 10 ) + { + fail("A total of 10 UsbPipeDataEvents and UsbPipeErrorEvents are expected, " + numDataEvents + + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a UsbControlIrp IN from the device. It submits the + * UsbControlIrp ten times, and checks that it got either a UsbPipeDataEvent + * or a UsbPipeErrorEvent back. If it gets a data event back, it compares + * the Irp in the data event to the Irp submitted and checks that the + * buffered data is not null, and if it gets an error event back, it makes + * sure that the exception in the event is not null. It also checks that + * the UsbControlIrp is complete immediately after the syncSubmit returns. + * @throws Exception + */ + public void testControlIOSyncSubmitIrp_IN() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_IN | + UsbConst.REQUESTTYPE_RECIPIENT_DEVICE; + byte bRequest = UsbConst.REQUEST_GET_DESCRIPTOR; + short wValue = + (short) ((UsbConst.DESCRIPTOR_TYPE_STRING * (short) 0x0100) | + 0x0001); + short wIndex = (short) 0x0000; + byte buffer[] = new byte[64]; + int usbCtrlIOIrpOffset; + int usbCtrlIOIrpLength; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer); + usbCtrlIOIrp.setAcceptShortPacket(false); + usbCtrlIOIrpOffset = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength = usbCtrlIOIrp.getLength(); + + assertFalse("IN Irp #" + (i+1) + ": UsbCotrolIrp should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + assertFalse("IN Irp #" + (i+1) + ": UsbControlIrp.getAcceptShortPacket should be set to false", + usbCtrlIOIrp.getAcceptShortPacket()); + + try + { + usbCtrlIOPipe.syncSubmit(usbCtrlIOIrp); + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for IN syncSubmit #" + (i+1)); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for IN syncSubmit #" + (i+1)); + } catch ( UsbException uE ) + { + assertNotNull("The IN syncSubmit UsbException should not be null", + uE); + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + assertEquals("The UsbException for the Irp should match the exception caught", + usbCtrlIOIrp.getUsbException(), uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + if ( !usbCtrlIOIrp.isComplete() ) + { + fail("IN Irp #" + (i+1) + ": The UsbControlIrp is not complete after syncSubmit"); + } + + for ( int j = 0; j < 400; j++ ) + { + Thread.sleep(5); + if ( numDataEvents + numErrorEvents > i ) + { + break; + } + } + if ( numDataEvents + numErrorEvents <= i ) + { + fail("No UsbPipeDataEvent or UsbPipeErrorEvent received"); + } + + assertNotNull("The IN UsbControlIrp data should not be NULL", + usbCtrlIOIrp.getData()); + assertEquals("The IN bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The IN bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The IN getOffset() shouldn't be altered", + usbCtrlIOIrpOffset, usbCtrlIOIrp.getOffset()); + assertEquals("The IN getLength() shouldn't be altered", + usbCtrlIOIrpLength, usbCtrlIOIrp.getLength()); + + if ( !usbCtrlIOIrp.isUsbException() ) + { + UsbPipeDataEvent lastUsbPipeDE = + (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + assertNotNull("The IN data event getData shouldn't be NULL", + lastUsbPipeDE.getData()); + assertTrue("The IN data event UsbIrp ActualLength should be >= 0", + lastUsbPipeDE.getUsbIrp().getActualLength() >= (byte) 0); + assertEquals("The IN data event UsbIrp getOffsetdoesn't match the IN Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The IN data event UsbIrp getLength doesn't match the IN Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The IN data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertNotNull("No USB Exception was embedded in the IN Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The IN error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + if ( numDataEvents + numErrorEvents > 10 ) + { + fail("A total of 10 UsbPipeDataEvents and UsbPipeErrorEvents are expected, " + numDataEvents + + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a list of UsbControlIrps OUT to the device. It submits + * the list, and checks that it got either got ten UsbPipeDataEvents (one + * for each Irp in the list) or no more than nine UsbPipeDataEvents and a + * UsbPipeErrorEvent back. For each data event it receives, it compares the + * Irp in the data event to the Irp submitted and checks that the buffered + * data did not change. For each error event received, it makes sure that + * the exception in the event is not null. It also checks that the + * UsbControlIrp is complete for all Irps in the list immediately after the + * syncSubmit returns. + * @throws Exception + */ + public void testControlIOSyncSubmitIrpList_OUT() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + UsbException exceptionReceived = null; + List usbCtrlIOIrpList = new ArrayList(); + int usbCtrlIOIrpOffset[] = new int[10]; + int usbCtrlIOIrpLength[] = new int[10]; + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_OUT | + UsbConst.REQUESTTYPE_RECIPIENT_ENDPOINT; + byte bRequest = UsbConst.REQUEST_CLEAR_FEATURE; + byte buffer[] = new byte[10]; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + short wValue = (short) 0x0000; + short wIndex = usbCtrlIOEndpointDesc.bEndpointAddress(); + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer,i,0); + usbCtrlIOIrpOffset[i] = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength[i] = usbCtrlIOIrp.getLength(); + + assertFalse("OUT Irp #" + (i+1) + " in List: UsbCotrolIrp in a list should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + usbCtrlIOIrpList.add((Object) usbCtrlIOIrp); + } + + try + { + usbCtrlIOPipe.syncSubmit(usbCtrlIOIrpList); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for OUT syncSubmit"); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for OUT syncSubmit"); + } catch ( UsbException uE ) + { + exceptionReceived = uE; + assertNotNull("The OUT syncSubmit UsbException should not be null", + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + for ( int i = 0; i < 4000; i++ ) + { + Thread.sleep(5); + if ( numDataEvents == 10 || numErrorEvents >= 1 ) + break; + } + if ( numDataEvents + numErrorEvents < 10 && numErrorEvents == 0 ) + fail("10 UsbPipeDataEvents or 0 or more UsbPipeDataEvents & 1 or more UsbPipeErrorEvents expected, " + + numDataEvents + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + else if ( numDataEvents + numErrorEvents > 10 ) + fail("A maximum total of 10 UsbPipeDataEvents & ErrorEvents were expected, " + + numDataEvents + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + + for ( int i = 0; i < 10; i++ ) + { + usbCtrlIOIrp = (UsbControlIrp)usbCtrlIOIrpList.remove(0); + + if ( i < numDataEvents + numErrorEvents ) + { + assertTrue("OUT Irp #" + (i+1) + " in List: The UsbControlIrp is not complete after syncSubmit", + usbCtrlIOIrp.isComplete()); + if ( i < numDataEvents ) + { + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } else + { + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + } + } else + { + assertFalse("OUT Irp #" + (i+1) + " in List: The UsbControlIrp should not be complete since it wasn't submitted", + usbCtrlIOIrp.isComplete()); + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } + + assertEquals("The OUT UsbControlIrp data should not be altered", + buffer, usbCtrlIOIrp.getData()); + assertEquals("The OUT bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The OUT bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The OUT getOffset() shouldn't be altered", + usbCtrlIOIrpOffset[i], usbCtrlIOIrp.getOffset()); + assertEquals("The OUT getLength() shouldn't be altered", + usbCtrlIOIrpLength[i], usbCtrlIOIrp.getLength()); + + if ( usbCtrlIOIrp.isComplete() && !usbCtrlIOIrp.isUsbException() ) + { + UsbPipeDataEvent lastUsbPipeDE = + (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + // TODO No idea why these two arrays should match. Ignoring for now + //assertEquals("The OUT data event getData doesn't match the OUT Irp getData", + // usbCtrlIOIrp.getData(), lastUsbPipeDE.getData()); + assertEquals("The OUT data event UsbIrp ActualLength doesn't match the OUT Irp ActualLenth", + usbCtrlIOIrp.getActualLength(), lastUsbPipeDE.getUsbIrp().getActualLength()); + assertEquals("The OUT data event UsbIrp getOffset doesn't match the OUT Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The OUT data event UsbIrp getLength doesn't match the OUT Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The OUT data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else if ( usbCtrlIOIrp.isUsbException() ) + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The OUT error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a list of UsbControlIrps IN from the device. It submits + * the list, and checks that it got either got ten UsbPipeDataEvents (one + * for each Irp in the list) or no more than nine UsbPipeDataEvents and a + * UsbPipeErrorEvent back. For each data event it receives, it compares the + * Irp in the data event to the Irp submitted and checks that the buffered + * data is not null. For each error event received, it makes sure that the + * exception in the event is not null. It also checks that the + * UsbControlIrp is complete for all Irps in the list immediately after the + * syncSubmit returns. + * @throws Exception + */ + public void testControlIOSyncSubmitIrpList_IN() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + UsbException exceptionReceived = null; + List usbCtrlIOIrpList = new ArrayList(); + int usbCtrlIOIrpOffset[] = new int[10]; + int usbCtrlIOIrpLength[] = new int[10]; + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_IN | + UsbConst.REQUESTTYPE_RECIPIENT_DEVICE; + byte bRequest = UsbConst.REQUEST_GET_DESCRIPTOR; + byte buffer[] = new byte[640]; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + short wValue = + (short) ((UsbConst.DESCRIPTOR_TYPE_STRING * (short) 0x0100) | + 0x0001); + short wIndex = (short) 0x0000; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer,(i*64),64); + usbCtrlIOIrp.setAcceptShortPacket(false); + usbCtrlIOIrpOffset[i] = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength[i] = usbCtrlIOIrp.getLength(); + + assertFalse("IN Irp #" + (i+1) + " in List: UsbCotrolIrp in a list should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + assertFalse("IN Irp #" + (i+1) + " in List: UsbControlIrp.getAcceptShortPacket should be set to false", + usbCtrlIOIrp.getAcceptShortPacket()); + usbCtrlIOIrpList.add((Object) usbCtrlIOIrp); + } + + try + { + usbCtrlIOPipe.syncSubmit(usbCtrlIOIrpList); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for IN syncSubmit"); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for IN syncSubmit"); + } catch ( UsbException uE ) + { + exceptionReceived = uE; + assertNotNull("The IN syncSubmit UsbException should not be null", + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + for ( int i = 0; i < 4000; i++ ) + { + Thread.sleep(5); + if ( numDataEvents == 10 || numErrorEvents >= 1 ) + break; + } + if ( numDataEvents + numErrorEvents < 10 && numErrorEvents == 0 ) + fail("10 UsbPipeDataEvents or 0 or more UsbPipeDataEvents & 1 or more UsbPipeErrorEvents expected, " + + numDataEvents + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + else if ( numDataEvents + numErrorEvents > 10 ) + fail("A maximum total of 10 UsbPipeDataEvents & ErrorEvents were expected, " + + numDataEvents + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + + for ( int i = 0; i < 10; i++ ) + { + usbCtrlIOIrp = (UsbControlIrp)usbCtrlIOIrpList.get(i); + + if ( i < numDataEvents + numErrorEvents ) + { + assertTrue("OUT Irp #" + (i+1) + " in List: The UsbControlIrp is not complete after syncSubmit", + usbCtrlIOIrp.isComplete()); + if ( i < numDataEvents ) + { + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } else + { + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + } + } else + { + assertFalse("OUT Irp #" + (i+1) + " in List: The UsbControlIrp should not be complete since it wasn't submitted", + usbCtrlIOIrp.isComplete()); + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } + + assertNotNull("The IN UsbControlIrp data should not be NULL", + usbCtrlIOIrp.getData()); + assertEquals("The IN bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The IN bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The IN getOffset() shouldn't be altered", + usbCtrlIOIrpOffset[i], usbCtrlIOIrp.getOffset()); + assertEquals("The IN getLength() shouldn't be altered", + usbCtrlIOIrpLength[i], usbCtrlIOIrp.getLength()); + + if ( usbCtrlIOIrp.isComplete() && !usbCtrlIOIrp.isUsbException() ) + { + UsbPipeDataEvent lastUsbPipeDE = + (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + assertNotNull("The IN data event getData shouldn't be NULL", + lastUsbPipeDE.getData()); + assertTrue("The IN data event ActualLength should be >= 0", + lastUsbPipeDE.getUsbIrp().getActualLength() >= (byte) 0); + assertEquals("The IN data event UsbIrp getOffset doesn't match the IN Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The IN data event UsbIrp getLength doesn't match the IN Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The IN data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else if ( usbCtrlIOIrp.isUsbException() ) + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The IN error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does an + * asyncSubmit with a UsbControlIrp OUT to the device. It submits the + * UsbControlIrp ten times, and checks thatit got either a UsbPipeDataEvent + * or a UsbPipeErrorEvent back. If it gets a data event back, it compares + * the Irp in the data event to the Irp submitted and checks that the + * buffered data did not change, and if it gets an error event back, it + * makes sure that the exception in the event is not null. It also checks + * that the UsbControlIrp is complete when waitForComplete(5000) is called + * on the UsbControlIrp after the asyncSubmit returns. + * @throws Exception + */ + public void testControlIOAsyncSubmitIrp_OUT() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_OUT | + UsbConst.REQUESTTYPE_RECIPIENT_ENDPOINT; + byte bRequest = UsbConst.REQUEST_CLEAR_FEATURE; + short wValue = (short) 0x0000; + short wIndex = usbCtrlIOEndpointDesc.bEndpointAddress(); + byte buffer[] = new byte[0]; + int usbCtrlIOIrpOffset; + int usbCtrlIOIrpLength; + int lastNumDataEvents = numDataEvents; + int lastNumErrorEvents = numErrorEvents; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer); + usbCtrlIOIrpOffset = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength = usbCtrlIOIrp.getLength(); + + assertFalse("OUT Irp #" + (i+1) + ": UsbCotrolIrp should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + + try + { + usbCtrlIOPipe.asyncSubmit(usbCtrlIOIrp); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for OUT asyncSubmit #" + (i+1)); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for OUT asyncSubmit #" + (i+1)); + } catch ( UsbException uE ) + { + assertNotNull("The OUT asyncSubmit UsbException should not be null", + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + usbCtrlIOIrp.waitUntilComplete(5000); + assertTrue("OUT Irp #" + (i+1) + ": The UsbCotrolIrp should be complete after waitUntilComplete", + usbCtrlIOIrp.isComplete()); + + for ( int j = 0; j < 400; j++ ) + { + Thread.sleep(5); + if ( numDataEvents + numErrorEvents > i ) + { + if ( numDataEvents > lastNumDataEvents ) + { + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } else + { + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + } + break; + } + } + if ( numDataEvents + numErrorEvents <= i ) + { + fail("No UsbPipeDataEvent or UsbPipeErrorEvent received"); + } + + assertEquals("The OUT UsbControlIrp data should not be altered", + buffer, usbCtrlIOIrp.getData()); + assertEquals("The OUT bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The OUT bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The OUT getOffset() shouldn't be altered", + usbCtrlIOIrpOffset, usbCtrlIOIrp.getOffset()); + assertEquals("The OUT getLength() shouldn't be altered", + usbCtrlIOIrpLength, usbCtrlIOIrp.getLength()); + + if ( !usbCtrlIOIrp.isUsbException() ) + { + UsbPipeDataEvent lastUsbPipeDE = + (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + // TODO No idea why these two arrays should match. Ignoring for now + //assertEquals("The OUT data event getData doesn't match the OUT Irp getData", + // usbCtrlIOIrp.getData(), lastUsbPipeDE.getData()); + assertEquals("The OUT data event UsbIrp ActualLength doesn't match the OUT Irp ActualLenth", + usbCtrlIOIrp.getActualLength(), lastUsbPipeDE.getUsbIrp().getActualLength()); + assertEquals("The OUT data event UsbIrp getOffset doesn't match the OUT Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The OUT data event UsbIrp getLength doesn't match the OUT Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The OUT data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The OUT error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + if ( numDataEvents + numErrorEvents > 10 ) + { + fail("A total of 10 UsbPipeDataEvents and UsbPipeErrorEvents are expected, " + numDataEvents + + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a UsbControlIrp IN from the device. It submits the + * UsbControlIrp ten times, and checks that it got either a UsbPipeDataEvent + * or a UsbPipeErrorEvent back. If it gets a data event back, it compares + * the Irp in the data event to the Irp submitted and checks that the + * buffered data is not null, and if it gets an error event back, it makes + * sure that the exception in the event is not null. It also checks that + * the UsbControlIrp is complete when waitForComplete(5000) is called on the + * UsbControlIrp after the asyncSubmit returns. + * @throws Exception + */ + public void testControlIOAsyncSubmitIrp_IN() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_IN | + UsbConst.REQUESTTYPE_RECIPIENT_DEVICE; + byte bRequest = UsbConst.REQUEST_GET_DESCRIPTOR; + short wValue = + (short) ((UsbConst.DESCRIPTOR_TYPE_STRING * (short) 0x0100) | + 0x0001); + short wIndex = (short) 0x0000; + byte buffer[] = new byte[64]; + int usbCtrlIOIrpOffset; + int usbCtrlIOIrpLength; + int lastNumDataEvents = numDataEvents; + int lastNumErrorEvents = numErrorEvents; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer); + usbCtrlIOIrp.setAcceptShortPacket(false); + usbCtrlIOIrpOffset = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength = usbCtrlIOIrp.getLength(); + + assertFalse("IN Irp #" + (i+1) + ": UsbCotrolIrp should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + assertFalse("IN Irp #" + (i+1) + ": UsbControlIrp.getAcceptShortPacket should be set to false", + usbCtrlIOIrp.getAcceptShortPacket()); + + try + { + usbCtrlIOPipe.asyncSubmit(usbCtrlIOIrp); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for IN asyncSubmit #" + (i+1)); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for IN asyncSubmit #" + (i+1)); + } catch ( UsbException uE ) + { + assertNotNull("The IN asyncSubmit UsbException should not be null", + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + usbCtrlIOIrp.waitUntilComplete(5000); + assertTrue("IN Irp #" + (i+1) + ": The UsbCotrolIrp should be complete after waitUntilComplete", + usbCtrlIOIrp.isComplete()); + + for ( int j = 0; j < 400; j++ ) + { + Thread.sleep(5); + if ( numDataEvents + numErrorEvents > i ) + { + if ( numDataEvents > lastNumDataEvents ) + { + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + } else + { + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + } + break; + } + } + if ( numDataEvents + numErrorEvents <= i ) + { + fail("No UsbPipeDataEvent or UsbPipeErrorEvent received"); + } + + assertNotNull("The IN UsbControlIrp data should not be NULL", + usbCtrlIOIrp.getData()); + assertEquals("The IN bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The IN bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The IN getOffset() shouldn't be altered", + usbCtrlIOIrpOffset, usbCtrlIOIrp.getOffset()); + assertEquals("The IN getLength() shouldn't be altered", + usbCtrlIOIrpLength, usbCtrlIOIrp.getLength()); + + if ( !usbCtrlIOIrp.isUsbException() ) + { + UsbPipeDataEvent lastUsbPipeDE = + (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + assertNotNull("The IN data event getData shouldn't be NULL", + lastUsbPipeDE.getData()); + assertTrue("The IN data event ActualLength should be >= 0", + lastUsbPipeDE.getUsbIrp().getActualLength() >= (byte) 0); + assertEquals("The IN data event UsbIrp getOffset doesn't match the IN Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The IN data event UsbIrp getLength doesn't match the IN Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The IN data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertNotNull("No USB Exception was embedded in the IN Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The IN error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + if ( numDataEvents + numErrorEvents > 10 ) + { + fail("A total of 10 UsbPipeDataEvents and UsbPipeErrorEvents are expected, " + numDataEvents + + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a list of UsbControlIrps OUT to the device. It submits + * the list, and checks that it got either a total of ten UsbPipeDataEvents + * and UsbPipeErrorEvents (a data event or error event for each Irp in the + * list) back. For each data event it receives, it compares the Irp in the + * data event to the Irp submitted and checks that the buffered data did not + * change. For each error event received it makes sure that the exception in + * the event is not null. It also checks that the UsbControlIrp is complete + * when waitForComplete(5000) is called on all UsbControlIrps in the list + * after the asyncSubmit returns. + * @throws Exception + */ + public void testControlIOAsyncSubmitIrpList_OUT() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + List usbCtrlIOIrpList = new ArrayList(); + int usbCtrlIOIrpOffset[] = new int[10]; + int usbCtrlIOIrpLength[] = new int[10]; + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_OUT | + UsbConst.REQUESTTYPE_RECIPIENT_ENDPOINT; + byte bRequest = UsbConst.REQUEST_CLEAR_FEATURE; + byte buffer[] = new byte[10]; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + e.printStackTrace(); + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + short wValue = (short) 0x0000; + short wIndex = usbCtrlIOEndpointDesc.bEndpointAddress(); + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer,i,0); + usbCtrlIOIrpOffset[i] = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength[i] = usbCtrlIOIrp.getLength(); + + assertFalse("OUT Irp #" + (i+1) + " in List: UsbCotrolIrp in a list should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + usbCtrlIOIrpList.add((Object) usbCtrlIOIrp); + } + + try + { + usbCtrlIOPipe.asyncSubmit(usbCtrlIOIrpList); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for OUT asyncSubmit"); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for OUT asyncSubmit"); + } catch ( UsbException uE ) + { + assertNotNull("The OUT asyncSubmit UsbException should not be null", + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + for ( int i = 0; i < 10; i++ ) + { + usbCtrlIOIrp = (UsbControlIrp)usbCtrlIOIrpList.get(i); + + usbCtrlIOIrp.waitUntilComplete(5000); + assertTrue("OUT Irp #" + (i+1) + " in List: The UsbControlIrp is not complete after waitForComplete", + usbCtrlIOIrp.isComplete()); + + for ( int j = 0; j < 400; j++ ) + { + Thread.sleep(5); + if ( numDataEvents + numErrorEvents > i ) + break; + } + } + + if ( numDataEvents + numErrorEvents != 10 ) + fail("A total of 10 UsbPipeDataEvents and UsbPipeDataEvents are expected, " + + numDataEvents + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + + for ( int i = 0; i < 10; i++ ) + { + usbCtrlIOIrp = (UsbControlIrp)usbCtrlIOIrpList.remove(0); + + assertEquals("The OUT UsbControlIrp data should not be altered", + buffer, usbCtrlIOIrp.getData()); + assertEquals("The OUT bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The OUT bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The OUT getOffset() shouldn't be altered", + usbCtrlIOIrpOffset[i], usbCtrlIOIrp.getOffset()); + assertEquals("The OUT getLength() shouldn't be altered", + usbCtrlIOIrpLength[i], usbCtrlIOIrp.getLength()); + + if ( LastUsbPipeDataEvent.size() > 0 ) + { + UsbPipeDataEvent lastUsbPipeDE = (UsbPipeDataEvent) LastUsbPipeDataEvent.get(0); + + if ( usbCtrlIOIrpOffset[i] == lastUsbPipeDE.getUsbIrp().getOffset() && + usbCtrlIOIrpLength[i] == lastUsbPipeDE.getUsbIrp().getLength() ) + { + lastUsbPipeDE = (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + // TODO No idea why these two arrays should match. Ignoring for now + //assertEquals("The OUT data event getData doesn't match the OUT Irp getData", + // usbCtrlIOIrp.getData(), lastUsbPipeDE.getData()); + assertEquals("The OUT data event UsbIrp ActualLength doesn't match the OUT Irp ActualLenth", + usbCtrlIOIrp.getActualLength(), lastUsbPipeDE.getUsbIrp().getActualLength()); + assertEquals("The OUT data event UsbIrp getOffset doesn't match the OUT Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The OUT data event UsbIrp getLength doesn't match the OUT Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The OUT data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else + { + UsbPipeErrorEvent lastUsbPipeEE = (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The OUT error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } else + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The OUT error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes a UsbPipe opened by the openControlIOPipe() method and does a + * syncSubmit with a list of UsbControlIrps IN from the device. It submits + * the list, and checks that it got either a total of ten UsbPipeDataEvents + * and UsbPipeErrorEvents (a data event or error event for each Irp in the + * list) back. For each data event it receives, it compares the Irp in the + * data event to the Irp submitted and checks that the buffered data is not + * null. For each error event received, it makes sure that the exception in + * the event is not null. It also checks that the UsbControlIrp is complete + * when waitForComplete(5000) is called on all UsbControlIrps in the list + * after the asyncSubmit returns. + * @throws Exception + */ + public void testControlIOAsyncSubmitIrpList_IN() throws Exception{ + UsbControlIrp usbCtrlIOIrp; + List usbCtrlIOIrpList = new ArrayList(); + int usbCtrlIOIrpOffset[] = new int[10]; + int usbCtrlIOIrpLength[] = new int[10]; + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_IN | + UsbConst.REQUESTTYPE_RECIPIENT_DEVICE; + byte bRequest = UsbConst.REQUEST_GET_DESCRIPTOR; + byte buffer[] = new byte[640]; + + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + + for ( int i = 0; i < 10; i++ ) + { + short wValue = + (short) ((UsbConst.DESCRIPTOR_TYPE_STRING * (short) 0x0100) | + 0x0001); + short wIndex = (short) 0x0000; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer,(i*64),64); + usbCtrlIOIrp.setAcceptShortPacket(false); + usbCtrlIOIrpOffset[i] = usbCtrlIOIrp.getOffset(); + usbCtrlIOIrpLength[i] = usbCtrlIOIrp.getLength(); + + assertFalse("IN Irp #" + (i+1) + " in List: UsbCotrolIrp in a list should not be complete before the submit", + usbCtrlIOIrp.isComplete()); + assertFalse("IN Irp #" + (i+1) + " in List: UsbControlIrp.getAcceptShortPacket should be set to false", + usbCtrlIOIrp.getAcceptShortPacket()); + usbCtrlIOIrpList.add((Object) usbCtrlIOIrp); + } + + try + { + usbCtrlIOPipe.asyncSubmit(usbCtrlIOIrpList); + } catch ( IllegalArgumentException uIAE ) + { + fail("The buffer is set to NULL for IN asyncSubmit"); + } catch ( UsbNotOpenException uNOE ) + { + fail("The pipe is not open for IN asyncSubmit"); + } catch ( UsbException uE ) + { + assertNotNull("The IN asyncSubmit UsbException should not be null", + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + + for ( int i = 0; i < 10; i++ ) + { + usbCtrlIOIrp = (UsbControlIrp)usbCtrlIOIrpList.get(i); + + usbCtrlIOIrp.waitUntilComplete(5000); + assertTrue("OUT Irp #" + (i+1) + " in List: The UsbControlIrp is not complete after waitForComplete", + usbCtrlIOIrp.isComplete()); + + for ( int j = 0; j < 400; j++ ) + { + Thread.sleep(5); + if ( numDataEvents + numErrorEvents > i ) + break; + } + } + + if ( numDataEvents + numErrorEvents != 10 ) + fail("A total of 10 UsbPipeDataEvents and UsbPipeDataEvents are expected, " + + numDataEvents + " UsbPipeDataEvents & " + numErrorEvents + " UsbPipeErrorEvents received"); + + for ( int i = 0; i < 10; i++ ) + { + usbCtrlIOIrp = (UsbControlIrp)usbCtrlIOIrpList.get(i); + + assertNotNull("The IN UsbControlIrp data should not be NULL", + usbCtrlIOIrp.getData()); + assertEquals("The IN bmRequestType shouldn't be altered", + bmRequestType, usbCtrlIOIrp.bmRequestType()); + assertEquals("The IN bRequest shouldn't be altered", + bRequest, usbCtrlIOIrp.bRequest()); + assertEquals("The IN getOffset() shouldn't be altered", + usbCtrlIOIrpOffset[i], usbCtrlIOIrp.getOffset()); + assertEquals("The IN getLength() shouldn't be altered", + usbCtrlIOIrpLength[i], usbCtrlIOIrp.getLength()); + + if ( LastUsbPipeDataEvent.size() > 0 ) + { + UsbPipeDataEvent lastUsbPipeDE = (UsbPipeDataEvent) LastUsbPipeDataEvent.get(0); + + if ( usbCtrlIOIrpOffset[i] == lastUsbPipeDE.getUsbIrp().getOffset() && + usbCtrlIOIrpLength[i] == lastUsbPipeDE.getUsbIrp().getLength() ) + { + lastUsbPipeDE = (UsbPipeDataEvent) LastUsbPipeDataEvent.remove(0); + + assertFalse("The usbCtrlIOIrp.isUsbException should be set to FALSE", + usbCtrlIOIrp.isUsbException()); + assertNotNull("The IN data event getData shouldn't be NULL", + lastUsbPipeDE.getData()); + assertTrue("The IN data event ActualLength should be >= 0", + lastUsbPipeDE.getUsbIrp().getActualLength() >= (byte) 0); + assertEquals("The IN data event UsbIrp getOffset doesn't match the IN Irp getOffset", + usbCtrlIOIrp.getOffset(), lastUsbPipeDE.getUsbIrp().getOffset()); + assertEquals("The IN data event UsbIrp getLength doesn't match the IN Irp getLength", + usbCtrlIOIrp.getLength(), lastUsbPipeDE.getUsbIrp().getLength()); + assertEquals("The IN data event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeDE.getUsbPipe()); + } else + { + UsbPipeErrorEvent lastUsbPipeEE = (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The IN error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } else + { + UsbPipeErrorEvent lastUsbPipeEE = + (UsbPipeErrorEvent) LastUsbPipeErrorEvent.remove(0); + + assertTrue("The usbCtrlIOIrp.isUsbException should be set to TRUE", + usbCtrlIOIrp.isUsbException()); + assertNotNull("No USB Exception was embedded in the OUT Error Event", + lastUsbPipeEE.getUsbException()); + assertEquals("The UsbException for the Irp should match the error event exception", + usbCtrlIOIrp.getUsbException(), lastUsbPipeEE.getUsbException()); + assertEquals("The IN error event UsbPipe doesn't match the UsbPipe submitted on", + usbCtrlIOPipe, lastUsbPipeEE.getUsbPipe()); + } + } + + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + } + + /** + * Takes an open UsbPipe and calls the UsbPipe.abortAllSubmissions method to + * test that it doesn't throw any exceptions on an open pipe. + * @throws Exception + */ + public void testAbortAllSubmissionsOpenPipe() throws Exception { + try + { + openControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening the Control I/O Pipe"); + } + assertTrue("The usbPipe.isOpen() method should be true on an open pipe", + usbCtrlIOPipe.isOpen()); + try + { + usbCtrlIOPipe.abortAllSubmissions(); + } catch ( UsbNotOpenException uNOE ) + { + fail("AbortAllSubmissions threw a UsbNotOpenException on an open pipe"); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } // @P1A + try + { + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while closing the Control I/O Pipe"); + } + assertFalse("The usbPipe.isOpen() method should be false on a closed pipe", + usbCtrlIOPipe.isOpen()); + } + + /** + * Takes a closed UsbPipe and calls the UsbPipe.abortAllSubmissions method + * to test that it throws a UsbNotOpenException on a closed pipe. + * @throws Exception + */ + public void testAbortAllSubmissionsClosedPipe() + { + try + { + openControlIOPipe(); + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening or closing the Control I/O Pipe"); + } + assertFalse("The usbPipe.isOpen() method should be false on a closed pipe", + usbCtrlIOPipe.isOpen()); + try + { + usbCtrlIOPipe.abortAllSubmissions(); + fail("abortAllSubmissions didn't throw a UsbNotOpenException on a closed pipe"); + } catch ( UsbNotOpenException uNOE ) + { + assertNotNull("The UsbNotOpenException shouldn't be null", + uNOE); + } + } + + /** + * Takes a closed UsbPipe and calls the UsbPipe.syncSubmit method with a + * UsbControlIrp to test that it throws a UsbNotOpenException on a closed + * pipe. + * @throws Exception + */ + public void testSyncSubmitClosedPipe() + { + try + { + openControlIOPipe(); + closeControlIOPipe(); + } catch ( Exception e ) + { + fail("There was an exception while opening or closing the Control I/O Pipe"); + } + assertFalse("The usbPipe.isOpen() method should be fale on a closed pipe", + usbCtrlIOPipe.isOpen()); + try + { + UsbControlIrp usbCtrlIOIrp; + byte bmRequestType = + UsbConst.REQUESTTYPE_TYPE_STANDARD | + UsbConst.ENDPOINT_DIRECTION_OUT | + UsbConst.REQUESTTYPE_RECIPIENT_ENDPOINT; + byte bRequest = UsbConst.REQUEST_CLEAR_FEATURE; + short wValue = (short) 0x0000; + short wIndex = usbCtrlIOEndpointDesc.bEndpointAddress(); + byte buffer[] = new byte[0]; + int usbCtrlIOIrpOffset; + int usbCtrlIOIrpLength; + + usbCtrlIOIrp = usbCtrlIOPipe.createUsbControlIrp(bmRequestType, bRequest, wValue, wIndex); + usbCtrlIOIrp.setData(buffer); + usbCtrlIOPipe.syncSubmit(usbCtrlIOIrp); + fail("syncSubmit didn't throw a UsbNotOpenException on a closed pipe"); + } catch ( UsbNotOpenException uNOE ) + { + assertNotNull("The UsbNotOpenException shouldn't be null", + uNOE); + } catch ( UsbException uE ) + { + fail("UsbNotOpenException expected. Submitting on a closed pipe should not throw a generic UsbException" + uE); + } catch ( UsbDisconnectedException uDE ) // @P1C + { // @P1A + fail ("A connected device should't throw the UsbDisconnectedException!"); // @P1A + } catch ( java.lang.IllegalArgumentException iAE ) // @P1C + { + fail("Submit should not throw IllegalArguementException w/valid Irp is used"); + } + } + + /** + * This method listens for all the UsbPipeDataEvents and UsbPipeErrorEvents + * and tests that they are not null. It then makes sure that the data and + * error events are available for the test cases above to access to ensure + * that they correspond to data or error events expected within the test + * cases. + */ + protected UsbPipeListener usbCtrlIOPipeListener = new UsbPipeListener() + { + public void dataEventOccurred(UsbPipeDataEvent uPDE) + { + numDataEvents++; + assertNotNull("The Data Event object shouldn't be null", uPDE); + LastUsbPipeDataEvent.add((Object) uPDE); + } + public void errorEventOccurred(UsbPipeErrorEvent uPEE) + { + numErrorEvents++; + assertNotNull("The Error Event object shouldn't be null", uPEE); + LastUsbPipeErrorEvent.add((Object) uPEE); + } + }; + + //************************************************************************** + // Private variables accessable between the tests + + private UsbDevice usbCtrlIODev; + private UsbInterface usbCtrlIOInterface; + private UsbInterfaceDescriptor usbCtrlIOInterfaceDesc; + private UsbEndpoint usbCtrlIOEndpoint; + private UsbEndpointDescriptor usbCtrlIOEndpointDesc; + private UsbPipe usbCtrlIOPipe; + private List LastUsbPipeDataEvent; + private List LastUsbPipeErrorEvent; + private int numDataEvents; + private int numErrorEvents; +} diff --git a/src/test/java/javax/usb/tck/FindControlIODevice.java b/src/test/java/javax/usb/tck/FindControlIODevice.java new file mode 100755 index 0000000..ad8b864 --- /dev/null +++ b/src/test/java/javax/usb/tck/FindControlIODevice.java @@ -0,0 +1,330 @@ +package javax.usb.tck; + +/** + * Copyright (c) IBM Corporation, 2004 + * All Rights Reserved. + * + * This software is provided and licensed under the terms and conditions + * of the Common Public License. + * http://oss.software.ibm.com/developerworks/opensource/license-cpl.html + * + */ + +/* + * Change Activity: See below. + * + * FLAG REASON RELEASE DATE WHO DESCRIPTION + * ---- -------- -------- ------ -------- ------------------------------------ + * 0000 nnnnnnn yymmdd Initial Development + * $P1 tck.rel1 041222 raulortz Redesign TCK to create base and optional + * tests. Separate setConfig, setInterface + * and isochronous transfers as optionals. + */ + +import java.util.*; +import javax.usb.*; +import javax.usb.util.*; + +import org.junit.runner.RunWith; + +import de.ailis.usb4java.TCKRunner; + +/** + * FindControlIODevice + *

+ * This Singleton class finds the first device with a UsbEndpoint with the type + * ENDPOINT_TYPE_CONTROL and returns the device. Used by the + * ControlIODevice class. + * usage: (FindControlIODevice.getInstance()).getControlIODevice() + * @author Joshua Lowry + */ + +@SuppressWarnings("all") +public class FindControlIODevice extends Object +{ + //-------------------------------------------------------------------------- + // Ctor(s) + // + + /** + * The constructor is protected as this is a singleton class. + */ + protected FindControlIODevice() + { + } + + //-------------------------------------------------------------------------- + // Public methods + // + + /** + * Creates and returns the sole instance of the FindControlIODevice class. + * @return FindControlIODevice + */ + public static FindControlIODevice getInstance() + { + if ( instance == null ) + { + instance = new FindControlIODevice(); + instance.init(); + } + return instance; + } + + //-------------------------------------------------------------------------- + // Protected methods + // + + /** Initializes the FindControlIODevice instance */ + protected void init() + { + // empty + } + + + //-------------------------------------------------------------------------- + // Public methods + // + + /** + * Finds the first device with a Control Pipe other than the default Control + * Pipe and returns it. Returns null if no such device is found. + * @return UsbDevice + */ + public UsbDevice getControlIODevice() + { + virtualRootUsbHub = getVirtualRootUsbHub(); + usbDevices = null; + // get all connected devices + if ( debug ) + { + usbDevices = getAllUsbDevices(virtualRootUsbHub); + System.out.println("Found " + usbDevices.size() + " devices total."); + } + usbDevices = getUsbDevicesWithCtrlEndpoint(virtualRootUsbHub); + if ( usbDevices.isEmpty() ) + { + if ( debug ) + { + System.out.println("List Empty"); + } + return null; + } else + { + // return the first item + return(UsbDevice)usbDevices.get(0); + } + } + + /** + * Finds a list of devices with a Control Pipe other than the default Cotrol + * Pipe and returns it. Returns null if no devices are found. + * @return UsbDevice + */ + public List getControlIODevicesList() + { + virtualRootUsbHub = getVirtualRootUsbHub(); + usbDevices = null; + // get all connected devices + if ( debug ) + { + usbDevices = getAllUsbDevices(virtualRootUsbHub); + System.out.println("Found " + usbDevices.size() + " devices total."); + } + usbDevices = getUsbDevicesWithCtrlEndpoint(virtualRootUsbHub); + if ( usbDevices.isEmpty() ) + { + if ( debug ) + { + System.out.println("List Empty"); + } + return null; + } + + // return the list + return usbDevices; + } + + //-------------------------------------------------------------------------- + // Private methods + // + + /* + * Get the virtual root UsbHub. + * @return + */ + private static UsbHub getVirtualRootUsbHub() + { + UsbServices services = null; + UsbHub virtualRootUsbHub = null; + + /* First we need to get the UsbServices. + * This might throw either an UsbException or SecurityException. + * A SecurityException means we're not allowed to access the USB bus, + * while a UsbException indicates there is a problem either in + * the javax.usb implementation or the OS USB support. + */ + try + { + services = UsbHostManager.getUsbServices(); + } catch ( UsbException uE ) + { + throw new RuntimeException("Error : " + uE.getMessage()); + } catch ( SecurityException sE ) + { + throw new RuntimeException("Error : " + sE.getMessage()); + } + + /* Now we need to get the virtual root UsbHub, + * everything is connected to it. The Virtual Root UsbHub + * doesn't actually correspond to any physical device, it's + * strictly virtual. Each of the devices connected to one of its + * ports corresponds to a physical host controller located in + * the system. Those host controllers are (usually) located inside + * the computer, e.g. as a PCI board, or a chip on the mainboard, + * or a PCMCIA card. The virtual root UsbHub aggregates all these + * host controllers. + * + * This also may throw an UsbException or SecurityException. + */ + try + { + virtualRootUsbHub = services.getRootUsbHub(); + } catch ( UsbException uE ) + { + throw new RuntimeException("Error : " + uE.getMessage()); + } catch ( SecurityException sE ) + { + throw new RuntimeException("Error : " + sE.getMessage()); + } + + return virtualRootUsbHub; + } + + + /* + * This forms an inclusive list of all UsbDevices connected to this + * UsbDevice. + *

+ * The list includes the provided device. If the device is also a hub, + * the list will include all devices connected to it, recursively. + * @param usbDevice The UsbDevice to use. + * @return + */ + private static List getAllUsbDevices(UsbDevice usbDevice) + { + List list = new ArrayList(); + + list.add(usbDevice); + + /* this is just normal recursion. Nothing special. */ + if ( usbDevice.isUsbHub() ) + { + List devices = ((UsbHub)usbDevice).getAttachedUsbDevices(); + for ( int i=0; i