IRPs

Whether reading or writing, the first thing you need to do is create an IRP. IRPs are instances of the UsbIrp interface. You can implement this interface directly or instantiate the javax.usb.util.DefaultUsbIrp class, but its normally simpler to use the createUsbIrp( ) factory method in the UsbPipe class:

public UsbIrp createUsbIrp( )

For an IRP created by this method, you only have to set the data storage array using setData( ):

public void setData(byte[] data); public void setData(byte[] data, int offset, int length);

The size of the array should match the endpoints maximum packet size:

int maxPacketSize = endpoint.getUsbEndpointDescriptor().wMaxPacketSize( ); byte[] buffer = new byte[maxPacketSize]; UsbIrp irp = pipe.createUsbIrp( ); irp.setData(buffer);

The offset is set to 0 and the length is the size of the data array. If you would prefer to use one larger array to support multiple IRPs, you can set the offset and the length appropriately to select slices of the array for each IRP, either in the constructor or with the setOffset( ) and setLength( ) methods:

public void setOffset(int offset); public void setLength(int length);

For example:

int maxPacketSize = endpoint.getUsbEndpointDescriptor().wMaxPacketSize( ); byte[] buffer = new byte[8192]; UsbIrp irp1 = pipe.createUsbIrp( ); irp1.setData(buffer); irp1.setOffset(0); irp1.setLength(maxPacketSize); UsbIrp irp2 = pipe.createUsbIrp( ); irp2.setData(buffer); irp2.setOffset(maxPacketSize); irp1.setLength(maxPacketSize); UsbIrp irp3 = pipe.createUsbIrp( ); irp3.setData(buffer); irp3.setOffset(3*maxPacketSize); irp3.setLength(maxPacketSize);

Because packets tend to be so small, youll often need to stuff your content into multiple successive IRPs. However, the last one won always have exactly the amount of data needed to fill a packet. Most devices recognize a shorter than expected packet as indicating the end of the data. You can use the setActualLength( ) method to specify that only a subset of the normal data array contains real data:

public void setActualLength(int length);

This is not the same as selecting a subarray with setLength( ). The entire array is still sent; its just that the actual IRP is modified so that the device knows not to consider some of it. If it happens that the data does exactly fill an integral number of IRPs, you may need to send a zero-length packet to tell the device that no more data is forthcoming. Details are device and protocol dependent.

Conversely, when receiving a packet, you may not get back quite as many bytes as you expected. The getActualLength( ) method tells you how many bytes the device actually sent:

public int getActualLength( );

If this is less than the length of the data array or subarray, the device has finished sending data. By default, most devices allow these short packets. However, a few devices require all IRPs to be full. If you e dealing with such a device, set the short packet policy to false:

public boolean getAcceptShortPacket( ); public void setAcceptShortPacket(boolean accept);

Its also possible that a problem has occurred on the bus or in the device and the data is not necessarily good. If so, the IRP is flagged with an exception. You can check for this condition with the isUsbException( ) method and retrieve the actual exception with getUsbException( ):

public boolean isUsbException( ); public UsbException getUsbException( ); public void setUsbException(UsbException usbException);

Yes, this is a very weird way of handling errorsnot very Java-like at all.

Before you read data out of an IRP you submitted asynchronously, you need to check that its complete; that is, that the device is finished with it. You do this with the isComplete( ) method:

public boolean isComplete( );

Alternatively, you can block until an IRP is complete with the waitUntilComplete( ) methods:

public void waitUntilComplete( ); public void waitUntilComplete(long timeout);

The first blocks indefinitely; the second blocks for a specified number of milliseconds. Neither approach is necessary for IRPs submitted synchronously, since that method always blocks as soon as the IRP is submitted.

You can also set the completion state of an IRP:

public void setComplete(boolean complete); public void complete( );

As youll see in the next example, this is useful if you want to reuse the same UsbIrp object since it allows you to uncomplete an IRP by passing false to setComplete( ).

Категории

© amp.flylib.com,