diff --git a/src/site/apt/quickstart.apt b/src/site/apt/quickstart.apt deleted file mode 100644 index 7deb3c4..0000000 --- a/src/site/apt/quickstart.apt +++ /dev/null @@ -1,206 +0,0 @@ - ----------------------------------------------------------------------------- - Quick start - ----------------------------------------------------------------------------- - -Quick start - -* Choose an API - - usb4java provides two different APIs you can work with: - - * The low-level (libusb) API - - * The high-level (javax.usb) API - - [] - - The high-level API simply implements the - {{{http://javax-usb.sourceforge.net/}javax.usb (JSR80) API}}. One advantage - of this API is that it is implementation-independent. So it is easy to - switch to a different javax.usb implementation later without changing your - code. Another advantage is that this API is object oriented and is much - easier to use for Java developers. The disadvantage is that the javax.usb - project is pretty old and currently looks inactive, maybe even dead. - - The low-level API closely follows the C API of the - {{{http://libusb.info/}libusb}} project. This API has the advantage that it - provides the same functionality as libusb does. And if you know the C API of - libusb then you will most likely feel right at home when using this API - with usb4java. The disadvantage is that you will have a hard time changing - your code when you later switch to a different Java USB library. - -* The low-level (libusb) API - -** API design - - The low-level API of usb4java closely follows the C API of the - {{{http://libusb.info/}libusb}} project. All global functions and - constants of are defined as static members of the class - {{{./apidocs/org/usb4java/LibUsb.html}org.usb4java.LibUsb}}. - All structures of are defined in separate classes which are named - similar to the original struct names but without underscores, with upper - case names and with the prefix removed. For example the struct - is defined in the class - {{{./apidocs/org/usb4java/DeviceHandle.html}DeviceHandle}}. Struct - members are represented by static methods in the corresponding class. - - The following notable differences exists between the and - the API: - - * in the configuration descriptor is named because - is a reserved word in Java. - - * in the configuration descriptor is named to - be compatible to the USB specification and because method names starting - with upper-case letters are quite unusual in Java. - - * Whenever libusb expects a byte pointer and a length you have to use - a direct Java NIO ByteBuffer instead. - - * Methods which are returning a string through a byte buffer which was - passed as argument have additional simplified overloaded method - equivalents which are returning a Java String directly. - - [] - -** Initialization/deinitialization - - Before using any usb4java functionality you must initialize libusb: - ----- -final Context context = new Context(); -int result = LibUsb.init(context); -if (result < 0) throw new RuntimeException("Unable to initialize libusb. Result=" + result); ----- - - Specifiying a context is optional. If your application only needs a single - libusb context then you can specify as context. - - Before your application terminates you should deinitialize libusb: - ----- -LibUsb.exit(context); ----- - - -** Find your device - - Your program most likely wants to communicate with a specific device so first - of all you have to find it. You have to get a list of all connected USB - devices and then check the vendor/product ids. Here is a method which can - be used for this purpose: - ----- -public Device findDevice(short vendorId, short productId) -{ - // Read the USB device list - DeviceList list = new DeviceList(); - int result = LibUsb.getDeviceList(null, list); - if (result < 0) throw new LibUsbException("Unable to get device list", result); - - try - { - // Iterate over all devices and scan for the right one - for (Device device: list) - { - DeviceDescriptor descriptor = new DeviceDescriptor(); - result = LibUsb.getDeviceDescriptor(device, descriptor); - if (result < 0) throw new LibUsbException("Unable to read device descriptor", result); - if (descriptor.idVendor() == vendorId && descriptor.idProduct() == productId) return device; - } - } - finally - { - // Ensure the allocated device list is freed - LibUsb.freeDeviceList(list, true); - } - - // Device not found - return null; -} ----- - - In your application it might be a little bit more complicated. Maybe you - have more than one device of the same type so you may need a list of devices. - Or you have to identify your device by the product or vendor string - descriptor instead of just checking the ID (In case you are using a - shared vendor/product ID). But this example should bring you on the right - track. - -** Device handles - - For the real USB communication you must open a new device handle and you - must close it again when you are finished communicating with the device. - Example: - ----- -DeviceHandle handle = new DeviceHandle(); -int result = LibUsb.open(device, handle); -if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to open USB device", result); -try -{ - // Use device handle here -} -finally -{ - LibUsb.close(handle); -} ----- - -** Interfaces - - Usually you are communicating with an interface provided by the USB device and - you have to claim this interface before using it and you have to release it - when you are finished. Example: - ----- -int result = LibUsb.claimInterface(handle, interfaceNumber); -if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to claim interface", result); -try -{ - // Use interface here -} -finally -{ - result = LibUsb.releaseInterface(handle, interfaceNumber); - if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to release interface", result); -} ----- - -** Communication - - For the actual USB communication you usually have to create a direct - byte buffer for the data to send or receive. Here is an example which - sends 8 bytes to a claimed interface unsing a control transfer: - ----- -ByteBuffer buffer = ByteBuffer.allocateDirect(8); -buffer.put(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); -int transfered = LibUsb.controlTransfer(handle, - (byte) (LibUsb.REQUEST_TYPE_CLASS | LibUsb.RECIPIENT_INTERFACE), - (byte) 0x09, (short) 2, (short) 1, buffer, 2500); -if (transfered < 0) - throw new LibUsbException("Control transfer failed", transfered); -if (transfered != message.length) - throw new RuntimeException("Not all data was sent to device"); ----- - - You may also want to use - {{{./apidocs/org/usb4java/LibUsb.html##bulkTransfer(org.usb4java.DeviceHandle, byte, java.nio.ByteBuffer, java.nio.IntBuffer, long)}bulkTransfer}} or - {{{./apidocs/org/usb4java/LibUsb.html##interruptTransfer(org.usb4java.DeviceHandle, byte, java.nio.ByteBuffer, java.nio.IntBuffer, long)}interruptTransfer}} - instead of - {{{./apidocs/org/usb4java/LibUsb.html##controlTransfer(org.usb4java.DeviceHandle, byte, byte, short, short, java.nio.ByteBuffer, long)}controlTransfer}} - - The parameters needed for the transfer calls are completely - device dependent so you have to check the device documentation for details. - -* See also - - * {{{./apidocs/org/usb4java/package-summary.html}API documentation of usb4java}} - - * {{{http://javax-usb.sourceforge.net/jdoc/}javax.usb (JSR80) API documentation}} - - * {{{http://libusb.sourceforge.net/api-1.0/}API documentation of libusb}} - - [] - \ No newline at end of file diff --git a/src/site/apt/quickstart/index.apt b/src/site/apt/quickstart/index.apt new file mode 100644 index 0000000..f6a36cc --- /dev/null +++ b/src/site/apt/quickstart/index.apt @@ -0,0 +1,37 @@ + ----------------------------------------------------------------------------- + Quick start + ----------------------------------------------------------------------------- + +Quick start + +* Choose an API + + usb4java provides two different APIs you can choose from: + + * {{{./libusb.html}The low-level (libusb) API}} + + * {{{./javax-usb.html}The high-level (javax-usb) API}} + + [] + + The low-level API closely follows the C API of the + {{{http://libusb.info/}libusb}} project. This API has the advantage that it + provides the same functionality as libusb does. And if you know the C API of + libusb then you will most likely feel right at home when using this API + with usb4java. It is also easy to convert existing C libusb programs into + Java. The disadvantage is that you will have a hard time changing + your code when you later switch to a different Java USB library. And as a + pure Java developer you may dislike the API because it is too low-level (For + example most methods return error codes instead of throwing exceptions). + + The high-level API simply implements the + {{{http://javax-usb.sourceforge.net/}javax-usb (JSR80) API}}. One advantage + of this API is that it is implementation-independent. So it is easy to + switch to a different javax-usb implementation later without changing your + code. Another advantage is that this API is object oriented and is much + easier to use for Java developers. The disadvantage is that the javax-usb + specification is pretty old and may lack support for some newer USB + techniques provided by the low-level API. + + + \ No newline at end of file diff --git a/src/site/apt/quickstart/javax-usb.apt b/src/site/apt/quickstart/javax-usb.apt new file mode 100644 index 0000000..e2e1aae --- /dev/null +++ b/src/site/apt/quickstart/javax-usb.apt @@ -0,0 +1,188 @@ + ----------------------------------------------------------------------------- + High-level (javax-usb) API + ----------------------------------------------------------------------------- + +High-level (javax-usb) API + + The high-level API implements the + {{{http://javax-usb.sourceforge.net/}javax-usb (JSR-80)}} standard. This API + is object-oriented, event-driven and uses exceptions for error-handling + instead of negative return values like the low-level API. Another advantage + is that you may switch to a different implementation later + without changing your code. For example instead of using you may + try out the reference implementation for Linux and Windows. + + +* Configuration + + To use the implementation you have to create a file named + <{{{./configuration.html}javax.usb.properties}}> in the root of your class + path with the following content: + ++-----------------------------------------------------------------------------+ +javax.usb.services = org.usb4java.javax.Services ++-----------------------------------------------------------------------------+ + + +* Finding USB devices + + USB devices are managed in a tree. The root of this tree is a virtual + USB hub to which all physical root hubs are connected. More hubs can be + connected to these root hubs and any hub can have a number of connected + USB devices. + + Often you need to search for a specific device before working with it. Here + is an example how to scan the device tree for the first device with a + specific vendor and product id. It can be easily expanded to check for + specific device classes or whatever: + ++-----------------------------------------------------------------------------+ +public UsbDevice findDevice(UsbHub hub, short vendorId, short productId) +{ + for (UsbDevice device : (List) hub.getAttachedUsbDevices()) + { + UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor(); + if (desc.idVendor() == vendorId && desc.idProduct() == productId) return device; + if (device.isUsbHub()) + { + device = findDevice((UsbHub) device, vendorId, productId); + if (device != null) return device; + } + } + return null; +} ++-----------------------------------------------------------------------------+ + + +* Control requests + + This example reads the current configuration number from a device by + using a control request: + ++-----------------------------------------------------------------------------+ +UsbControlIrp irp = device.createUsbControlIrp( + (byte) (UsbConst.REQUESTTYPE_DIRECTION_IN + | UsbConst.REQUESTTYPE_TYPE_STANDARD + | UsbConst.REQUESTTYPE_RECIPIENT_DEVICE), + UsbConst.REQUEST_GET_CONFIGURATION, + (short) 0, + (short) 0 + ); +irp.setData(new byte[1]); +device.syncSubmit(irp); +System.out.println(irp.getData()[0]); ++-----------------------------------------------------------------------------+ + + +* Interfaces + + When you want to communicate with an interface or with endpoints of this + interface then you have to claim it before using it and you have to + release it when you are finished. Example: + +---- +UsbConfiguration configuration = device.getActiveUsbConfiguration(); +UsbInterface iface = configuration.getUsbInterface((byte) 1); +iface.claim(); +try +{ + ... Communicate with the interface or endpoints ... +} +finally +{ + iface.release(); +} +---- + + It is possible that the interface you want to communicate with is already + used by a kernel driver. In this case you can try to force the claiming by + passing an interface policy to the <<>> method: + +---- +iface.claim(new UsbInterfacePolicy() +{ + @Override + public boolean forceClaim(UsbInterface usbInterface) + { + return true; + } +}); +---- + + Please note that interface policies are just a hint for the underlying USB + implementation. In case of the policy will be ignored on Windows + because doesn't support detaching drivers on Windows. + +* Synchronous I/O + + This example sends 8 bytes to endpoint 0x03: + +---- +UsbEndpoint endpoint = iface.getUsbEndpoint(0x03); +UsbPipe pipe = endpoint.getUsbPipe(); +pipe.open(); +try +{ + int sent = pipe.syncSubmit(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); + System.out.println(sent + " bytes sent"); +} +finally +{ + pipe.close(); +} +---- + + This example reads 8 bytes from endpoint 0x83: + +---- +UsbEndpoint endpoint = iface.getUsbEndpoint((byte) 0x83); +UsbPipe pipe = endpoint.getUsbPipe(); +pipe.open(); +try +{ + byte[] data = new byte[8]; + int received = pipe.syncSubmit(data); + System.out.println(received + " bytes received"); +} +finally +{ + pipe.close(); +} +---- + +* Asynchronous I/O + + Asynchronous I/O works pretty much the same as synchronous I/O. You just + use the <<>> methods instead of the <<>> methods. + While <<>> blocks until the request is complete + <<>> does not block and return immediately. To + receive the response you have to add a listener to the pipe like this: + +---- +pipe.addUsbPipeListener(new UsbPipeListener() +{ + @Override + public void errorEventOccurred(UsbPipeErrorEvent event) + { + UsbException error = event.getUsbException(); + ... Handle error ... + } + + @Override + public void dataEventOccurred(UsbPipeDataEvent event) + { + byte[] data = event.getData(); + ... Process received data ... + } +}); +---- + +* See also + + * {{{../usb4java-javax/apidocs/index.html}API documentation of usb4java-javax}} + + * {{{https://github.com/usb4java/usb4java-javax-examples/}usb4java-javax examples}} + + * {{{http://javax-usb.sourceforge.net/}javax-usb website}} + + [] \ No newline at end of file diff --git a/src/site/apt/quickstart/libusb.apt b/src/site/apt/quickstart/libusb.apt new file mode 100644 index 0000000..87bb017 --- /dev/null +++ b/src/site/apt/quickstart/libusb.apt @@ -0,0 +1,327 @@ + ----------------------------------------------------------------------------- + Low-level (libusb) API + ----------------------------------------------------------------------------- + +Low-level (libusb) API + +* API design + + The low-level API of usb4java closely follows the C API of the + {{{http://libusb.info/}libusb}} project. All global functions and + constants of are defined as static members of the class + {{{../apidocs/org/usb4java/LibUsb.html}org.usb4java.LibUsb}}. + All structures of are defined in separate classes which are named + similar to the original struct names but without underscores, with camel-case + names and with the prefix removed. For example the struct + is defined in the class + {{{../apidocs/org/usb4java/DeviceHandle.html}DeviceHandle}}. Struct + members are represented by static methods in the corresponding class. + + The following notable differences exists between the and + the API: + + * in the configuration descriptor is named because + is a reserved word in Java. + + * in the configuration descriptor is named to + be compatible to the USB specification and because method names starting + with upper-case letters are quite unusual in Java. + + * Whenever libusb expects a byte pointer and a length you have to use + a direct Java NIO ByteBuffer instead. + + * Methods which are returning a string through a byte buffer which was + passed as argument have additional simplified overloaded method + equivalents which are returning a Java String directly. + + [] + +* Initialization/deinitialization + + Before using any usb4java functionality you must initialize libusb: + +---- +Context context = new Context(); +int result = LibUsb.init(context); +if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to initialize libusb.", result); +---- + + Specifiying a context is optional. If your application only needs a single + libusb context then you can specify as context. + + Before your application terminates you should deinitialize libusb: + +---- +LibUsb.exit(context); +---- + + Related libusb documentation: + + * {{{http://libusb.sourceforge.net/api-1.0/group__lib.html}Library initialization/deinitialization}} + + [] + +* Finding USB devices + + Your program most likely wants to communicate with a specific device so first + of all you have to find it. You have to get a list of all connected USB + devices and then check the vendor/product ids. Here is a method which can + be used for this purpose: + +---- +public Device findDevice(short vendorId, short productId) +{ + // Read the USB device list + DeviceList list = new DeviceList(); + int result = LibUsb.getDeviceList(null, list); + if (result < 0) throw new LibUsbException("Unable to get device list", result); + + try + { + // Iterate over all devices and scan for the right one + for (Device device: list) + { + DeviceDescriptor descriptor = new DeviceDescriptor(); + result = LibUsb.getDeviceDescriptor(device, descriptor); + if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to read device descriptor", result); + if (descriptor.idVendor() == vendorId && descriptor.idProduct() == productId) return device; + } + } + finally + { + // Ensure the allocated device list is freed + LibUsb.freeDeviceList(list, true); + } + + // Device not found + return null; +} +---- + + In your application it might be a little bit more complicated. Maybe you + have more than one device of the same type so you may need a list of devices. + Or you have to identify your device by the product or vendor string + descriptor instead of just checking the ID (In case you are using a + shared vendor/product ID). But this example should bring you on the right + track. + + Related libusb documentation: + + * {{{http://libusb.sourceforge.net/api-1.0/group__dev.html}Device handling and enumeration}} + + [] + +* Device handles + + For the real USB communication you must open a new device handle and you + must close it again when you are finished communicating with the device. + Example: + +---- +DeviceHandle handle = new DeviceHandle(); +int result = LibUsb.open(device, handle); +if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to open USB device", result); +try +{ + // Use device handle here +} +finally +{ + LibUsb.close(handle); +} +---- + +* Interfaces + + When you want to communicate with an interface or with endpoints of this + interface then you have to claim it before using it and you have to + release it when you are finished. Example: + +---- +int result = LibUsb.claimInterface(handle, interfaceNumber); +if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to claim interface", result); +try +{ + // Use interface here +} +finally +{ + result = LibUsb.releaseInterface(handle, interfaceNumber); + if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to release interface", result); +} +---- + + It is possible that the interface you want to communicate with is already + used by a kernel driver. In this case you have to detach the kernel driver + from the interface before claiming it. Example: + +---- +// Check if kernel driver must be detached +boolean detach = LibUsb.hasCapability(LibUsb.CAP_SUPPORTS_DETACH_KERNEL_DRIVER) + && LibUsb.kernelDriverActive(handle, interfaceNumber); + +// Detach the kernel driver +if (detach) +{ + int result = LibUsb.detachKernelDriver(handle, interfaceNumber); + if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to detach kernel driver", result); +} + +// Communicate with the device +... + +// Attach the kernel driver again if needed +if (detach) +{ + int result = LibUsb.attachKernelDriver(handle, interfaceNumber); + if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to re-attach kernel driver", result); +} +---- + + Please note that detaching kernel drivers is not supported on Windows. + +* Synchronous I/O + + For the actual USB communication you usually have to create a direct + byte buffer for the data to send or receive. + + This examples sends 8 bytes to a claimed interface using a control transfer: + +---- +ByteBuffer buffer = ByteBuffer.allocateDirect(8); +buffer.put(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); +int transfered = LibUsb.controlTransfer(handle, + (byte) (LibUsb.REQUEST_TYPE_CLASS | LibUsb.RECIPIENT_INTERFACE), + (byte) 0x09, (short) 2, (short) 1, buffer, timeout); +if (transfered < 0) throw new LibUsbException("Control transfer failed", transfered); +System.out.println(transfered + " bytes sent"); +---- + + This example sends 8 bytes to endpoint 0x03 of the claimed interface using a + bulk transfer: + +---- +ByteBuffer buffer = ByteBuffer.allocateDirect(8); +buffer.put(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); +IntBuffer transfered = IntBuffer.allocate(1); +int result = LibUsb.bulkTransfer(handle, 0x03, buffer, transfered, timeout); +if (result != LibUsb.SUCCESS) throw new LibUsbException("Control transfer failed", transfered); +System.out.println(transfered.get() + " bytes sent"); +---- + + Related libusb documentation: + + * {{{http://libusb.sourceforge.net/api-1.0/group__syncio.html}Synchronous device I/O}} + + [] + +* Asynchronous I/O + + Asynchronous I/O is a little bit more complex than synchronous I/O. That's + because libusb doesn't start its own thread to + handle the actual background tasks. Instead you have to create you own + worker thread like this: + +---- +class EventHandlingThread extends Thread +{ + /** If thread should abort. */ + private volatile boolean abort; + + /** + * Aborts the event handling thread. + */ + public void abort() + { + this.abort = true; + } + + @Override + public void run() + { + while (!this.abort) + { + int result = LibUsb.handleEventsTimeout(null, 250000); + if (result != LibUsb.SUCCESS) + throw new LibUsbException("Unable to handle events", result); + } + } +} +---- + + This simple thread implementation doesn't use a specific libusb context so + it specified <<>> as context. If you need contexts then you may want + to pass it to the thread somehow. + + The thread must be started after you have initialized libusb: + +---- +EventHandlingThread thread = new EventHandlingThread(); +thread.start(); +---- + + And it must be stopped before deinitializing libusb: + +---- +thread.abort(); +thread.join(); +---- + + So now with this thread running in the background you can use the + asynchronous functions of libusb. If you don't like this thread and your + program already has some kind of application loop then you can also simply + call <<>> inside the loop. This call + returns immediately if there are no events to process. + + An actual asynchronous transfer is submitted like this (In this case + an outgoing bulk transfer to endpoint <0x03>): + +---- +ByteBuffer buffer = BufferUtils.allocateByteBuffer(8); +buffer.put(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); +Transfer transfer = LibUsb.allocTransfer(); +LibUsb.fillBulkTransfer(transfer, handle, 0x03, buffer, callback, null, timeout); +int result = LibUsb.submitTransfer(transfer); +if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to submit transfer", result); +---- + + The <<>> is an object implementing the + {{{../apidocs/org/usb4java/TransferCallback.html}TransferCallback}} interface. + Here is an example of such a callback: + +---- +TransferCallback callback = new TransferCallback() +{ + @Override + public void processTransfer(Transfer transfer) + { + System.out.println(transfer.actualLength() + " bytes sent"); + LibUsb.freeTransfer(transfer); + } +}; +---- + + Related libusb documentation: + + * {{{http://libusb.sourceforge.net/api-1.0/group__asyncio.html}Asynchronous device I/O}} + + * {{{http://libusb.sourceforge.net/api-1.0/mtasync.html}Multi-threaded applications and asynchronous I/O}} + + * {{{http://libusb.sourceforge.net/api-1.0/io.html}Synchronous and asynchronous device I/O}} + + * {{{http://libusb.sourceforge.net/api-1.0/group__poll.html}Polling and timing}} + + [] + + + +* See also + + * {{{../apidocs/org/usb4java/package-summary.html}API documentation of usb4java}} + + * {{{https://github.com/usb4java/usb4java-examples/}usb4java examples}} + + * {{{http://libusb.sourceforge.net/api-1.0/}API documentation of libusb}} + + [] + \ No newline at end of file diff --git a/src/site/site.xml b/src/site/site.xml index a735e46..532dfd7 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -31,7 +31,10 @@ - + + + + diff --git a/src/site/xdoc/index.xml.vm b/src/site/xdoc/index.xml.vm index 943aca6..2e77a26 100644 --- a/src/site/xdoc/index.xml.vm +++ b/src/site/xdoc/index.xml.vm @@ -10,7 +10,7 @@ the native libusb 1.0 library and uses Java NIO buffers for data exchange between libusb and Java. usb4java also supports the - javax.usb standard (JSR-80) + javax-usb standard (JSR-80) through the usb4java-javax extension.

@@ -30,7 +30,7 @@ ${project.artifactId}-${project.version}.zip

  • - javax.usb extension:
    + javax-usb extension:
    ${project.artifactId}-javax-${usb4javaJavaxVersion}.tar.bz2
    ${project.artifactId}-javax-${usb4javaJavaxVersion}.zip
  • @@ -52,7 +52,7 @@ </repository> </repositories> -<-- For using just usb4java without javax.usb --> +<-- For using just usb4java without javax-usb --> <dependencies> <dependency> <groupId>${project.groupId}</groupId> @@ -61,7 +61,7 @@ </dependency> </dependencies> -<-- For using usb4java with javax.usb --> +<-- For using usb4java with javax-usb --> <dependencies> <dependency> <groupId>${project.groupId}</groupId> @@ -89,11 +89,11 @@

    - Read the quick start guide and the + Read the quick start guide and the FAQ. There are also some low-level (libusb) examples and - high-level (javax.usb) examples + high-level (javax-usb) examples available.