Skip to content

Commit

Permalink
Merge branch 'jdk22'
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelbl committed Mar 17, 2024
2 parents 688b26d + 0d912c3 commit 9abda6c
Show file tree
Hide file tree
Showing 275 changed files with 23,984 additions and 15,782 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/continuous-integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v3
uses: oracle-actions/setup-java@v1
with:
distribution: 'zulu'
java-version: '21'
cache: 'maven'
website: jdk.java.net
release: 22
version: latest
- name: Configure GPG key
run: |
echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
Expand Down
95 changes: 55 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,10 @@

[![javadoc](https://javadoc.io/badge2/net.codecrete.usb/java-does-usb/javadoc.svg)](https://javadoc.io/doc/net.codecrete.usb/java-does-usb)

*Java Does USB* is a Java library for working with USB devices. It allows to query information about all conntected USB devices and to communicate with USB devices using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.)
*Java Does USB* is a Java library for working with USB devices. It allows to query the conntected USB devices and to communicate with them using custom / vendor specific protocols. (It is not intended for communication with standard types of USB devices such as mass storage devices, keyboards etc.)

The library uses the [Foreign Function & Memory API](https://github.com/openjdk/panama-foreign) to access native APIs of the underlying operating system. It is written entirely in Java and does not need JNI or any native third-party library. The *Foreign Function & Memory API* (aka as project Panama) is currently in preview and will leave preview with Java 22. Currently, it can be used with Java 19, Java 20 or Java 21 (with preview features enabled).
The library uses the [Foreign Function and Memory API](https://docs.oracle.com/en/java/javase/21/core/foreign-function-and-memory-api.html#GUID-FBE990DA-C356-46E8-9109-C75567849BA8) to access native APIs of the underlying operating system. It is written entirely in Java and does not use JNI or any native third-party library. The *Foreign Function and Memory API* has been introduced with Java 22. Preview versions were available in several earlier releases.

| Version | Main New Features | Compatibility |
| - | - | - |
| 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 |
| 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 |
| 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 |
| 0.4.x | Early release | JDK 19 |

*Note: The main branch and published versions ≥ 0.6.0 work with JDK 21 only. For JDK 20, use version 0.5.*. For JDK 19, use version 0.4.x.


## Features
Expand All @@ -25,17 +17,8 @@ The library uses the [Foreign Function & Memory API](https://github.com/openjdk/
- Descriptive information about interfaces, settings and endpoints
- High-throughput input/output streams
- Support for alternate interface settings, composite devices and interface association
- Published on Maven Central

### Planned

- Isochronous transfer

### Not planned
- Published on Maven Central and licensed under the permissive MIT license

- Changing configuration: The library selects the first configuration. Changing configurations is rarely used and not supported on Windows (limitation of WinUSB).
- USB 3.0 streams: Not supported on Windows (limitation of WinUSB).
- Providing information about USB buses, controllers and hubs


## Getting Started
Expand All @@ -48,14 +31,14 @@ If you are using Maven, add the below dependency to your pom.xml:
<dependency>
<groupId>net.codecrete.usb</groupId>
<artifactId>java-does-usb</artifactId>
<version>0.7.1</version>
<version>1.0.0-SNAPSHOT</version>
</dependency>
```

If you are using Gradle, add the below dependency to your build.gradle file:

```groovy
compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '0.7.1'
compile group: 'net.codecrete.usb', name: 'java-does-usb', version: '1.0.0-SNAPSHOT'
```

```java
Expand All @@ -74,11 +57,14 @@ public class EnumerateDevices {
```



## Documentation

- [Javadoc](https://javadoc.io/doc/net.codecrete.usb/java-does-usb)




## Examples

- [Bulk Transfer](examples/bulk_transfer/) demonstrates how to find a USB device, open it and communicate using bulk transfer.
Expand All @@ -88,29 +74,29 @@ public class EnumerateDevices {
- [ePaper Display](examples/epaper_display) communicates with an IT8951 controller for e-Paper displays and shows an image on the display.



## Prerequisite

- Java 21, preview features enabled (available at https://www.azul.com/downloads/?package=jdk)
- Java 22 available at [jdk.java.net](https://jdk.java.net/21/), [Azul](https://www.azul.com/downloads/?package=jdk), [Adoptium](https://adoptium.net/temurin/releases/) or with your favorite package manager.
- Windows (x86 64-bit), macOS (x86 64-bit, ARM 64-bit) or Linux 64 bit (x86 64-bit, ARM 64-bit)

For JDK 20, use the latest published version 0.5.x. For JDK 19, use the latest published version 0.4.x.


## Platform-specific Considerations


### macOS

No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation-system drivers can be unloaded if the application is run with root privileges.
No special considerations apply. Using this library, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded if the application is run with root privileges. It runs both on Macs with Apple Silicon and Intel processors.


### Linux

*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement.
*libudev* is used to discover and monitor USB devices. It is closely tied to *systemd*. So the library only runs on Linux distributions with *systemd* and the related libraries. The majority of Linux distributions suitable for desktop computing (as opposed to distributions optimized for containers) fulfill this requirement. It runs on both Intel and ARM64 processors.

Similar to macOS, a Java application can connect to any USB device and claim any interfaces that isn't claimed by an operating system driver or another application. Standard operation system drivers can be unloaded (without the need for root privileges).

Most Linux distributions by default set up user accounts without permissions to access USB devices directly. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership:
Most Linux distributions set up user accounts without permissions to access USB devices. The *udev* system daemon is responsible for assigning permissions to USB devices. It can be configured to assign specific permissions or ownership:

Create a file called `/etc/udev/rules.d/80-javadoesusb-udev.rules` with the below content:

Expand All @@ -120,35 +106,55 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="cafe", MODE="0666"

This adds the rule to assign permission mode 0666 to all USB devices with vendor ID `0xCAFE`. This unregistered vendor ID is used by the test devices.

Without the *udev* rule, it is still possible to enumerate and query all USB devices.


### Windows

The Windows driver model is more rigid than the ones of macOS or Linux. It's not possible to open any USB device that is not claimed. Instead, only devices using the *WinUSB* driver can be opened. This even applies to devices with no installed driver.
The Windows driver model is rather rigid. It's not possible to open any USB device unless it uses the *WinUSB* driver. This even applies to devices with no installed driver. Enumerating and querying USB devices is possible independent of the driver.

USB devices can implement certain control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/).
USB devices can implement special control requests to instruct Windows to automatically install the WinUSB driver (search for *WCID* or *Microsoft OS Compatibility Descriptors*). The WinUSB driver can also be manually installed or replaced using a software called [Zadig](https://zadig.akeo.ie/).

The test devices implement the required control requests. So the driver is installed automatically.

The library has not been tested on Windows for ARM64. It might or might not work.
Windows for ARM64 is not yet supported. A port is probably easy, provided you have hardware to test it.


### Troubleshooting

#### `ClassFormatError` (all platforms)
## Troubleshooting

The error `java.lang.ClassFormatError: Illegal field name "" in class net/codecrete/usb/windows/WindowsUsbDeviceRegistry` is caused by a bug in JDK 21, which has been fixed in the mean-time. Please upgrade to the latest release of JDK 21 (at least 21.0.1).
### 32-bit versions

The *Foreign Function And Memory API* has not been implemented for 32-bit operating systems / JDKs (and likely never will be).


### 32-bit versions

The Foreign Function & Memory API has not been implemented for 32-bit operating systems / JDKs (and likely never will be).
## Running on older JDK versions

The *Foreign Function And Memory API* has been available as a preview feature in JDKs before 22. However, incompatible changes were made from preview to preview to release. Earlier versions can be used with specific versions of this library:

| Version | Main New Features | Compatibility |
| - | - | - |
| 1.0.x | Release for final Java API | JDK 22 |
| 0.7.x | New setter/getter names for improved Kotlin support; Kotlin examples | JDK 21 |
| 0.6.x | Support for JDK 21; better handling of composite devices on Windows | JDK 21 |
| 0.5.x | Support for JDK 20; high-throuput I/O streams | JDK 20 |
| 0.4.x | Early release | JDK 19 |

## Code generation
When using an older JDK, preview features must be enabled using the `--enable-preview` VM option.

Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. For functions that need to retain the error state (`errno` on Linux, `GetLastError()` on Windows), the bindings have been manually written as *jextract* does not support it.


## Building from source

To build from source, run the following command:

```
cd java-does-usb
mvn clean install -DskipTests
```

The tests are skipped as they require that a special test device is connected to the computer. See the next section for more information.



Expand All @@ -164,17 +170,26 @@ The test device with the *loopback-stm32* code supports all tests. If the test d
Tests can be run from the command line:

```
cd java-does-usb
mvn clean test
```

If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to enable preview features and allow native access:
If they are run from an IDE (such as IntelliJ IDEA), you must likely configure VM options to allow native access:

```
--enable-preview --enable-native-access=net.codecrete.usb
--enable-native-access=net.codecrete.usb
```

Or (if modules are ignored):

```
--enable-preview --enable-native-access=ALL-UNNAMED
--enable-native-access=ALL-UNNAMED
```



## Code generation

Many bindings for the native APIs have been generated with *jextract*. See the [jextract](java-does-usb/jextract) subdirectory for more information. For functions that need to retain the error state (`errno` on Linux, `GetLastError()` on Windows), the bindings have been manually written as *jextract* does not support it.

Since the code can only be generated for the current operating system, it must be generated on separate computers for Linux, Windows and macOS. Thus, the generated code is included in the repository. The generated code is compilable on all operating systems.
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
24 changes: 11 additions & 13 deletions examples/bulk_transfer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ This sample shows how to find a device, open it and transfer data from and to bu

## Prerequisites

- Java 21
- Java 22
- Apache Maven
- 64-bit operating system (Windows, macOS, Linux)
- A USB device with bulk IN and OUT endpoints (e.g. the test device, see https://github.com/manuelbl/JavaDoesUSB/tree/main/test-devices/loopback-stm32)

## How to run

### Install Java 21
### Install Java 22

Check that *Java 21* is installed:
Check that *Java 22* is installed:

```shell
$ java -version
Expand All @@ -39,24 +39,22 @@ $ mvn compile exec:exec
[INFO] Scanning for projects...
[INFO]
[INFO] --------------< net.codecrete.usb.examples:bulk-transfer >--------------
[INFO] Building bulk-transfer 0.7.1
[INFO] Building bulk-transfer 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ bulk-transfer ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/me/Documents/JavaDoesUSB/examples/bulk_transfer/src/main/resources
[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ bulk-transfer ---
[INFO] skip non existing resourceDirectory /home/user/Documents/JavaDoesUSB/examples/bulk_transfer/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ bulk-transfer ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/me/Documents/JavaDoesUSB/examples/bulk_transfer/target/classes
[INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ bulk-transfer ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ bulk-transfer ---
[INFO] --- exec-maven-plugin:3.1.1:exec (default-cli) @ bulk-transfer ---
6 bytes sent.
6 bytes received.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.259 s
[INFO] Finished at: 2023-03-23T14:10:17+01:00
[INFO] Total time: 1.228 s
[INFO] Finished at: 2024-02-18T16:23:29+01:00
[INFO] ------------------------------------------------------------------------
```
Loading

0 comments on commit 9abda6c

Please sign in to comment.