# JAVA hid4java for MacOs
###### tags: `Java` `hid4java` `Usb`
## 安裝使用
因為 hid4java 是透過 JNA 打包
所以需要安裝這兩個依賴
hid4java 0.5.0
JNA 4.2.2
可以直接用maven安裝就可
```
<!-- hid4java for cross-platform HID USB -->
<dependency>
<groupId>org.hid4java</groupId>
<artifactId>hid4java</artifactId>
<version>0.5.0</version>
</dependency>
```
Mac必須先把 https://github.com/libusb/hidapi 安裝到系統環境變數路徑下,才可以編譯,否則會報錯
我是直接安裝到 /Library/Java/Extensions 下
## 測試 LED mini badge 範例:
```
package com.leo.test;
import java.util.concurrent.TimeUnit;
import org.hid4java.HidDevice;
import org.hid4java.HidException;
import org.hid4java.HidManager;
import org.hid4java.HidServices;
import org.hid4java.HidServicesListener;
import org.hid4java.HidServicesSpecification;
import org.hid4java.ScanMode;
import org.hid4java.event.HidServicesEvent;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
public class UsbHidDeviceExample implements HidServicesListener {
private static final Integer VENDOR_ID = 0x416;
private static final Integer PRODUCT_ID = 0x5020;
// private static final Integer VENDOR_ID = 0x204c;
// private static final Integer PRODUCT_ID = 0x4359;
private static final int PACKET_LENGTH = 64;
public static final String SERIAL_NUMBER = null;
public static void main(String[] args) throws HidException {
UsbHidDeviceExample example = new UsbHidDeviceExample();
example.executeExample();
}
public void executeExample() throws HidException {
// Configure to use custom specification
HidServicesSpecification hidServicesSpecification = new HidServicesSpecification();
hidServicesSpecification.setAutoShutdown(true);
hidServicesSpecification.setScanInterval(500);
hidServicesSpecification.setPauseInterval(5000);
hidServicesSpecification.setScanMode(ScanMode.SCAN_AT_FIXED_INTERVAL_WITH_PAUSE_AFTER_WRITE);
// Get HID services using custom specification
HidServices hidServices = HidManager.getHidServices(hidServicesSpecification);
hidServices.addHidServicesListener(this);
// Start the services
System.out.println("Starting HID services.");
hidServices.start();
System.out.println("Enumerating attached devices...");
// Provide a list of attached devices
for (HidDevice hidDevice : hidServices.getAttachedHidDevices()) {
System.out.println(hidDevice);
}
// Open the device device by Vendor ID and Product ID with wildcard serial number
HidDevice hidDevice = hidServices.getHidDevice(VENDOR_ID, PRODUCT_ID, SERIAL_NUMBER);
if (hidDevice != null) {
System.out.println("find devices.....");
System.out.println(hidDevice.getUsage());
System.out.println(hidDevice.getId());
System.out.println(hidDevice.getUsagePage());
// Consider overriding dropReportIdZero on Windows
// if you see "The parameter is incorrect"
// HidApi.dropReportIdZero = true;
// Device is already attached and successfully opened so send message
sendMessage(hidDevice);
}
System.out.printf("Waiting 30s to demonstrate attach/detach handling. Watch for slow response after write if configured.%n");
// Stop the main thread to demonstrate attach and detach events
sleepUninterruptibly(10, TimeUnit.SECONDS);
// Shut down and rely on auto-shutdown hook to clear HidApi resources
hidServices.shutdown();
}
@Override
public void hidDeviceAttached(HidServicesEvent event) {
System.out.println("Device attached: " + event);
// Add serial number when more than one device with the same
// vendor ID and product ID will be present at the same time
if (event.getHidDevice().isVidPidSerial(VENDOR_ID, PRODUCT_ID, null)) {
sendMessage(event.getHidDevice());
}
}
@Override
public void hidDeviceDetached(HidServicesEvent event) {
System.err.println("Device detached: " + event);
}
@Override
public void hidFailure(HidServicesEvent event) {
System.err.println("HID failure: " + event);
}
private void sendMessage(HidDevice hidDevice) {
// Ensure device is open after an attach/detach event
if (!hidDevice.isOpen()) {
System.out.println("open hidDevice");
hidDevice.open();
}
// Send the Initialise message
byte[] message = new byte[PACKET_LENGTH];
message[0] = 0x3f; // USB: Payload 63 bytes
message[1] = 0x23; // Device: '#'
message[2] = 0x23; // Device: '#'
message[3] = 0x00; // INITIALISE
// String string = "1b00e006f46208d2ffff0000000009000001000d0001014000000077616e67000000003021324354667788000900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
// String string2 = "1b00e096bc6208d2ffff0000000009000001000d00010140000000e1a2a7e8aeaaeea4a4a6a90080c020e0a0e04040c020021f09091f000f09090f093ca42828b0282424242c2000030001000300030001028aef084cabefaacf92";
// String string3 = "1b005030346208d2ffff0000000009000001000d000101400000001222008000800080008000000072077d057700770577557740d05040f05050202050902828b0282424242c2000030001000300030001028aef084cabefaacf92";
// A 文字
String string = "1b00d047be0007e7ffff0000000009000001002e0001014000000077616e67000000004046474840444647000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
String string2 = "1b00d097010107e7ffff0000000009000001002e0001014000000000386cc6c6fec6c6c6c6004840444647000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
// String string = "1b0010d0a46208d2ffff00000000090000010015000101400000004c4359f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
// String string2 = "1b0020a87e6208d2ffff00000000090000010015000101400000004c4359dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
// String string3 = "1b00b092fb5f08d2ffff000000000900000100150001014000000000000000000000020201030001000000000000c8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
// String string4 = "1b00d087ad6208d2ffff0000000009000001001500010140000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
// String string5 = "1b00e0f11e6208d2ffff0000000009000001001500010140000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
// String string6 = "1b00a007436208d2ffff0000000009000001001500010140000000ffffffffffffffff009245d4555504c33320aaaa282aaa0caaaaa8ccccecccccdc0410100c3ae0eeaa902800a800000000000000000000000000000000000000";
// String string7 = "1b0090d7ac6208d2ffff000000000900000100150001014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
// String string8 = "1b005030516108d2ffff00000000090000010015000101400000004c435999000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
String packetString = string.substring(54);
String packetString2 = string2.substring(54);
// String packetString3 = string3.substring(54);
// String packetString4 = string.substring(54);
// String packetString5 = string2.substring(54);
// String packetString6 = string3.substring(54);
// String packetString7 = string.substring(54);
// String packetString8 = string2.substring(54);
byte[] packet1 = new byte[packetString.length() / 2];
for (int i = 0; i < packet1.length; i++) {
int index = i * 2;
int j = Integer.parseInt(packetString.substring(index, index + 2), 16);
packet1[i] = (byte) j;
}
byte[] packet2 = new byte[packetString2.length() / 2];
for (int i = 0; i < packet2.length; i++) {
int index = i * 2;
int j = Integer.parseInt(packetString2.substring(index, index + 2), 16);
packet2[i] = (byte) j;
}
// byte[] packet3 = new byte[packetString3.length() / 2];
// for (int i = 0; i < packet3.length; i++) {
// int index = i * 2;
// int j = Integer.parseInt(packetString3.substring(index, index + 2), 16);
// packet3[i] = (byte) j;
// }
// byte[] packet4 = new byte[packetString4.length() / 2];
// for (int i = 0; i < packet4.length; i++) {
// int index = i * 2;
// int j = Integer.parseInt(packetString4.substring(index, index + 2), 16);
// packet4[i] = (byte) j;
// }
// byte[] packet5 = new byte[packetString5.length() / 2];
// for (int i = 0; i < packet5.length; i++) {
// int index = i * 2;
// int j = Integer.parseInt(packetString5.substring(index, index + 2), 16);
// packet5[i] = (byte) j;
// }
// byte[] packet6 = new byte[packetString6.length() / 2];
// for (int i = 0; i < packet6.length; i++) {
// int index = i * 2;
// int j = Integer.parseInt(packetString6.substring(index, index + 2), 16);
// packet6[i] = (byte) j;
// }
// byte[] packet7 = new byte[packetString7.length() / 2];
// for (int i = 0; i < packet7.length; i++) {
// int index = i * 2;
// int j = Integer.parseInt(packetString7.substring(index, index + 2), 16);
// packet7[i] = (byte) j;
// }
// byte[] packet8 = new byte[packetString8.length() / 2];
// for (int i = 0; i < packet8.length; i++) {
// int index = i * 2;
// int j = Integer.parseInt(packetString8.substring(index, index + 2), 16);
// packet8[i] = (byte) j;
// }
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
// byte c[];
// try {
// outputStream.write( packet1 );
// outputStream.write( packet2 );
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// c = outputStream.toByteArray( );
// byte[] bytes = {-1, 0, 1, 2, 3 };
// StringBuilder sb = new StringBuilder();
// for (byte b : c) {
// sb.append(String.format("%02X ", b));
// }
int val = hidDevice.write(packet1, 64, (byte) 0x00);
int val2 = hidDevice.write(packet2, 64, (byte) 0x00);
// int val3 = hidDevice.write(packet3, 64, (byte) 0x00);
// int val4 = hidDevice.write(packet4, 64, (byte) 0x00);
// int val5 = hidDevice.write(packet5, 64, (byte) 0x00);
// int val6 = hidDevice.write(packet6, 64, (byte) 0x00);
// int val7 = hidDevice.write(packet7, 64, (byte) 0x00);
// int val8 = hidDevice.write(packet8, 64, (byte) 0x00);
if (val >= 0) {
System.out.println("> [" + val + "]");
} else {
System.err.println(hidDevice.getLastErrorMessage());
}
// Prepare to read a single data packet
boolean moreData = true;
while (moreData) {
byte data[] = new byte[PACKET_LENGTH];
// This method will now block for 500ms or until data is read
val = hidDevice.read(data, 500);
switch (val) {
case -1:
System.err.println(hidDevice.getLastErrorMessage());
break;
case 0:
moreData = false;
break;
default:
System.out.print("< [");
for (byte b : data) {
System.out.printf(" %02x", b);
}
System.out.println("]");
break;
}
}
}
/**
* Invokes {@code unit.}{@link java.util.concurrent.TimeUnit#sleep(long) sleep(sleepFor)}
* uninterruptibly.
*/
public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) {
boolean interrupted = false;
try {
long remainingNanos = unit.toNanos(sleepFor);
long end = System.nanoTime() + remainingNanos;
while (true) {
try {
// TimeUnit.sleep() treats negative timeouts just like zero.
NANOSECONDS.sleep(remainingNanos);
return;
} catch (InterruptedException e) {
interrupted = true;
remainingNanos = end - System.nanoTime();
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
}
```