Java要存取到OS上面USB device相關的資訊本身不支援,一種是透過JNI的方式,讓Java呼叫C來幫忙存取,而C現成的library可以想到知名的libusb。在這邊使用的usb4java就是基於libusb來開發,可以說是libusb for java的代表,目前也有列在libusb的github上! 可惜的是在2018年後就沒有再出新版本,但並不影響今日要實作的部分,因為只有用到list出目前電腦上有哪些連接的USB devices,來偵測當下有哪些裝置plug or unplug!
定義存放USB device的Vendor ID、Product ID、bus number、port number及device address等資訊
此抽象類別需定義getConnectedDevices method要做什麼處理,當下傳入的usbDeviceList為目前正連接著的USB device,用一個timer每3秒輪詢一次作為間隔,以此達到隨時detect是否有新插入或移除的裝置!
主程式提供一操作,分別為啟動USB detect server及列出目前連接的裝置及終止程式運作
首先,請至usb4java github下載目前最新的v1.3.0版本,解壓縮後將
commons-lang3-3.8.1.jar
libusb4java-1.3.0-win32-x86-64.jar (在此以Windows環境開發)
usb4java-1.3.0.jar
等加入到build path內
再來說明程式碼的部分:
#UsbDevice.java
import java.util.Objects;
public class UsbDevice {
private short vid;
private short pid;
private int bus;
private int port;
private int device;
public UsbDevice(int bus, int port, int device, short vid, short pid){
this.bus = bus;
this.port = port;
this.device = device;
this.vid = vid;
this.pid = pid;
}
public short getVid() {
return vid;
}
public short getPid() {
return pid;
}
public int getDevice() {
return device;
}
public void setDevice(int device) {
this.device = device;
}
public int getBus() {
return bus;
}
public int getPort() {
return port;
}
@Override
public int hashCode() {
return Objects.hash(bus, device, port);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UsbDevice other = (UsbDevice) obj;
return bus == other.bus && device == other.device && port == other.port;
}
@Override
public String toString() {
return "UsbDevice [vid=" + String.format("0x%04x", vid) + ", pid=" + String.format("0x%04x", pid) + ", bus=" + bus + ", port=" + port + ", device=" + device +"]";
}
}
定義存放USB device的Vendor ID、Product ID、bus number、port number及device address等資訊
從Vendor ID、Product ID可以得知是否為相同的USB裝置
從bus number、port number及device address可以得知插入的位置
這邊的equals是判斷哪些device被插入或移除
#UsbDeviceDetectService.java
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.usb4java.Context;
import org.usb4java.Device;
import org.usb4java.DeviceDescriptor;
import org.usb4java.DeviceList;
import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;
public abstract class UsbDeviceDetectService {
private boolean enabled = false;
private Timer timer;
private Context context = new Context();
protected abstract void getConnectedDevices(List<UsbDevice> usbDeviceList);
protected void addUsbServicesListener() {
timer = new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
DeviceList list = new DeviceList();
List<UsbDevice> plugTemp = new ArrayList<>();
int result = LibUsb.getDeviceList(context, list);
if (result < 0) {
cancel();
throw new LibUsbException("Unable to get device list", result);
}
// Iterate over all devices and scan for the right one
try {
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);
UsbDevice usbDevice = new UsbDevice(LibUsb.getBusNumber(device), LibUsb.getPortNumber(device), LibUsb.getDeviceAddress(device),
descriptor.idVendor(), descriptor.idProduct());
plugTemp.add(usbDevice);
}
getConnectedDevices(plugTemp);
} finally{
// Ensure the allocated device list is freed
LibUsb.freeDeviceList(list, true);
}
}
}, 0 , 3000);
}
public void removeUsbServicesListener() {
LibUsb.exit(context);
context = null;
if(timer != null){
timer.cancel();
timer = null;
}
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
if (this.enabled) {
int result = LibUsb.init(context);
if (result != LibUsb.SUCCESS)
throw new LibUsbException("Unable to initialize libusb.", result);
addUsbServicesListener();
} else {
removeUsbServicesListener();
}
}
}
此抽象類別需定義getConnectedDevices method要做什麼處理,當下傳入的usbDeviceList為目前正連接著的USB device,用一個timer每3秒輪詢一次作為間隔,以此達到隨時detect是否有新插入或移除的裝置!
#Main.java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
private List<UsbDevice> connectedLists = new ArrayList<>();
public static void main(String[] args) {
// TODO Auto-generated method stub
new Main();
}
public Main() {
UsbDeviceDetectService service = new UsbDeviceDetectService() {
boolean firstDetected = true;
@Override
protected void getConnectedDevices(List<UsbDevice> usbDeviceList) {
// TODO Auto-generated method stub
for(UsbDevice device : usbDeviceList) {
if(!connectedLists.contains(device)) {
connectedLists.add(device);
if(!firstDetected) {
System.out.println(">> Plug: "+device);
}
}
}
firstDetected = false;
if(connectedLists.size() > usbDeviceList.size()) {
List<UsbDevice> unplugList = new ArrayList<>();
for(UsbDevice device : connectedLists) {
if(!usbDeviceList.contains(device)) {
unplugList.add(device);
System.out.println("<< Unplug: "+device);
}
}
connectedLists.removeAll(unplugList);
}
}
};
Scanner input = new Scanner(System.in);
try {
while(true) {
System.out.println("(1)Start USB Service(2)List Connected Devices(3)Terminate");
int option = input.nextInt();
if(option == 1) {
if(!service.isEnabled()) {
service.setEnabled(true);
System.out.println("Start USB Detect Listener");
}else {
System.out.println("USB Detect has been started");
}
}else if(option == 2) {
System.out.println("Connected Devices:");
for(UsbDevice device : connectedLists) {
System.out.println(device);
}
}else if(option == 3) {
if(service.isEnabled()) {
service.setEnabled(false);
System.out.println("Terminate and remove USB Detect Listener");
break;
}else {
System.out.println("Terminate");
}
}else {
continue;
}
System.out.println();
}
} finally {
input.close();
}
}
}
主程式提供一操作,分別為啟動USB detect server及列出目前連接的裝置及終止程式運作
其覆寫的getConnectedDevices method內簡單判斷目前什麼裝置plug or unplug,並撇除了啟動USB detect時本身已插著的裝置
執行結果如下:
留言
張貼留言