Я пытаюсь сделать небольшой драйвер для связи с USB-термометром, используя java-библиотеку Libusb (org.usb4java.LibUsb). Я тестирую его на Raspeberry Pi (3b) с vanilla linux-arm.
Моя проблема в том, что мне не удается передать передачу управления на устройство. Я получаю сообщение об ошибке:
org.usb4java.LibUsbException: ошибка USB 9: ошибка передачи управления: ошибка канала
Вот мой код:
Основной класс:
public class usbDriver {
public static void main(String[] args) {
Communication2 com = new Communication2();
try {
com.trouverDevice();
com.preparerCom();
com.testCom();
com.terminerCom();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Связь2 класс:
public class Communication2 {
/** vendor ID du thermometre */
private static final short VENDOR_ID = 0x1941;
/** product ID du thermometre */
private static final short PRODUCT_ID = (short) 0x8021;
/** interface active du thermometre */
private static final byte INTERFACE_ID = 0x0;
/** endpoint sur l'interface active du thermometre */
private static final byte ENDPOINT_ID = (byte) 0x81;
private Context contexte = null;
private Device device = null;
DeviceHandle handle = null;
private boolean pret;
private boolean detach = false;
private boolean trouve = false;
public Communication2() {
pret = false;
}
public void trouverDevice() throws SecurityException, UsbException{
// avec libUsb
// Create the libusb context
Context context = new Context();
// Initialize the libusb context
int result = LibUsb.init(context);
if (result < 0)
{
throw new LibUsbException("Unable to initialize libusb", result);
}
// Read the USB device list
DeviceList list = new DeviceList();
result = LibUsb.getDeviceList(context, list);
if (result < 0)
{
throw new LibUsbException("Unable to get device list", result);
}
try
{
// Iterate over all devices and list them
for (Device device: list)
{
int address = LibUsb.getDeviceAddress(device);
int busNumber = LibUsb.getBusNumber(device);
DeviceDescriptor descriptor = new DeviceDescriptor();
result = LibUsb.getDeviceDescriptor(device, descriptor);
if (result < 0)
{
throw new LibUsbException(
"Unable to read device descriptor", result);
}
if (descriptor.idVendor() == VENDOR_ID && descriptor.idProduct() == PRODUCT_ID){
System.out.println("Thermometre Pearl NC-7004 detecté !");
System.out.println(descriptor.toString());
this.device = device;
this.trouve=true;
}
}
}
finally
{
// Ensure the allocated device list is freed
//LibUsb.freeDeviceList(list, true);
}
// Deinitialize the libusb context
}
public boolean preparerCom() throws Exception{
if (!this.trouve) return false;
this.contexte = new Context();
int result = LibUsb.init(contexte);
// reclamer le handle
System.out.println("claim device handle");
this.handle = new DeviceHandle();
result = LibUsb.open(this.device, handle);
if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to open USB device", result);
detach = LibUsb.hasCapability(LibUsb.CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
detach = true; // pour forcer le claim sur le kernel
detach = detach && (LibUsb.kernelDriverActive(handle, INTERFACE_ID)==1?true:false);
System.out.println(LibUsb.hasCapability(LibUsb.CAP_SUPPORTS_DETACH_KERNEL_DRIVER));
System.out.println((LibUsb.kernelDriverActive(handle, INTERFACE_ID)));
System.out.println(detach);
// Detach the kernel driver
if (detach)
{
System.out.println("tentative de detacher le kernel");
result = LibUsb.detachKernelDriver(handle, INTERFACE_ID);
if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to detach kernel driver", result);
}
detach = true;
System.out.println("claim interface");
result = LibUsb.claimInterface(handle, INTERFACE_ID);
if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to claim interface", result);
this.pret=false;
return this.pret;
}
public void testCom(){
if (!this.pret) return;
ByteBuffer buffer = ByteBuffer.allocate(18);
// LibUsb.fillControlSetup(buffer, (byte)0x80, (byte)0x6,
// (short)0x1, (short)0x0, (short)0x1200);
ByteBuffer buffer2 = ByteBuffer.allocateDirect(18);
int transfered = LibUsb.controlTransfer(handle,(byte)0x80,(byte)0x6,(short)0x1,(short)0x0,buffer2,2000L);
if (transfered < 0) throw new LibUsbException("Control transfer failed", transfered);
System.out.println(transfered + " bytes sent");
String test;
String test2;
if (buffer2.hasArray()) {
for(int i =0;i<buffer2.array().length;i++){
System.out.format("%02x",buffer2.array()[i]);
}
test= new String(buffer.array(),
buffer.arrayOffset() + buffer.position(),
buffer.remaining());
} else {
final byte[] b = new byte[buffer.remaining()];
buffer.duplicate().get(b);
test = new String(b);
}
System.out.println(test);
}
public void terminerCom() throws Exception{
if (this.pret){
if (this.detach)
{
int result = LibUsb.attachKernelDriver(handle, INTERFACE_ID);
if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to re-attach kernel driver", result);
}
LibUsb.close(this.handle);
this.trouve = false;
this.pret = false;
}
}
}
Ошибка возникает, когда я звоню LibUsb.ControlTransfer()
, пытаясь передать контрольный пакет GET_DESCRIPTOR
. Вот полный возврат кода с информацией об дескрипторе устройства:
> Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 Per Interface
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x1941
idProduct 0x8021
bcdDevice 1.00
iManufacturer 0
iProduct 0
iSerial 0
bNumConfigurations 1
claim device handle
false
0
false
claim interface
org.usb4java.LibUsbException: USB error 9: Control transfer failed: Pipe error
at usbDriver.Communication2.testCom(Communication2.java:171)
at usbDriver.usbDriver.main(usbDriver.java:36)
root@raspberrypi:/home/pi/Desktop/execUsbDriver# java -jar usbDriver_executable.jar
java.lang.IllegalArgumentException: handle must not be null
at org.usb4java.LibUsb.controlTransfer(Native Method)
at usbDriver.Communication2.testCom(Communication2.java:170)
at usbDriver.usbDriver.main(usbDriver.java:36)
Я думаю, что канал хорошо инициализирован (дескриптор кажется в порядке, интерфейс тоже успешно заявлен). Также документ Libusb указывает:
LIBUSB_ERROR_PIPE
если запрос на управление не поддерживался устройством
Так что, я думаю, я просто неправильно выполняю запрос на управление. Если вы знаете код для правильной отправки запроса GET_DESCRIPTOR
, я был бы рад его протестировать!