我正在尝试使用java库Libusb(org.usb4java.LibUsb)让一个小驱动程序与USB温度计进行通信。我正在使用vanilla linux-arm在Raspeberry Pi(3b)上测试它。
我的问题是我没有成功将控制转移传输到设备。我收到错误:
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();
}
}
}
Communication2课程:
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)
我认为管道初始化很好(Handle似乎没问题,界面也成功声明了)。 Libusb doc也指出:
LIBUSB_ERROR_PIPE
如果控件请求不受支持 设备
所以我想我只是错误地控制了控制请求。如果您知道正确发送GET_DESCRIPTOR
请求的代码,我很乐意对其进行测试!
答案 0 :(得分:1)
实际上我设法在我的设备上运行第一个请求!这只是发送请求的一个问题,这是不准确的。
不,我想处理主要目标:从温度计中检索数据。使用嗅探工具,我看到我必须通过控制管道发送一个设置包+8个字节的变量。然后在端点0x81上,器件应在中断模式下发回4 * 8字节的数据。我用原型工具测试了它:
当我不明白时,我应该做同步转移。我现在尝试了以下代码但没有成功。
public void testCom(){
if (!this.pret) return;
ByteBuffer buffer = ByteBuffer.allocateDirect(18);
buffer.rewind();
// descriptor device
int transfered = LibUsb.controlTransfer(handle,
LibUsb.ENDPOINT_IN,LibUsb.REQUEST_GET_DESCRIPTOR,(short)0x0100,(short)0x0000,buffer,2000L);
if (transfered < 0) throw new LibUsbException("Control transfer failed", transfered);
System.out.println(transfered + " bytes sent");
System.out.println("--- DEVICE DESCRIPTOR ---");
System.out.println(byteBuffer2String(buffer));
System.out.println();
buffer = ByteBuffer.allocateDirect(9);
// descriptor configuration
transfered = LibUsb.controlTransfer(handle,
LibUsb.ENDPOINT_IN,LibUsb.REQUEST_GET_DESCRIPTOR,(short)0x0200,(short)0x0000,buffer,2000L);
if (transfered < 0) throw new LibUsbException("Control transfer failed", transfered);
System.out.println(transfered + " bytes sent");
System.out.println("--- CONFIGURATION DESCRIPTOR ---");
System.out.println(byteBuffer2String(buffer));
System.out.println();
buffer = ByteBuffer.allocateDirect(8);
// descriptor string
transfered = LibUsb.controlTransfer(handle,
LibUsb.ENDPOINT_IN,LibUsb.REQUEST_GET_DESCRIPTOR,(short)0x0300,(short)0x0409,buffer,2000L);
if (transfered < 0) throw new LibUsbException("Control transfer failed", transfered);
System.out.println(transfered + " bytes sent");
System.out.println("--- DESCRIPTOR STRING ---");
System.out.println(byteBuffer2String(buffer));
System.out.println();
System.out.println("TRYING TO GET DATA ...");
ByteBuffer bufferArgCmd = ByteBuffer.allocateDirect(16);
/*bufferArgCmd.put((byte)0x21);
bufferArgCmd.put((byte)0x09);
bufferArgCmd.put((byte)0x02);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x08);
bufferArgCmd.put((byte)0x00);*/
bufferArgCmd.put((byte)0xA1);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x20);
bufferArgCmd.put((byte)0xA1);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x00);
bufferArgCmd.put((byte)0x20);
bufferArgCmd.rewind();
ByteBuffer bufferResCmd = ByteBuffer.allocateDirect(4);
bufferResCmd.get();
bufferResCmd.get();
ByteBuffer bufferData = ByteBuffer.allocateDirect(32);
ByteBuffer buffer81 = BufferUtils.allocateByteBuffer(32);
// buffer81.put(data);
Transfer transfer = LibUsb.allocTransfer(0);
LibUsb.fillInterruptTransfer(transfer, handle, ENDPOINT_ID, bufferData,
receiveData, null, 3000L);
LibUsb.fillControlSetup(bufferArgCmd,(byte)0x21,(byte)0x09,(short)0x0200,(short)0x0,(short)0x08);
// LibUsb.fillControlTransfer(transfer, handle, bufferArgCmd,
// sendData, null, 2000L);
System.out.println("doing interrupt transfer to device");
int result = LibUsb.submitTransfer(transfer);
if (result != LibUsb.SUCCESS)
{
throw new LibUsbException("Unable to submit transfer", result);
}
System.out.println("Resultat du transfert : ");
System.out.println(byteBuffer2String(bufferData));
}
// This callback is called after the ADB CONNECT message header is
// sent and sends the ADB CONNECT message body.
final TransferCallback receiveData = new TransferCallback()
{
@Override
public void processTransfer(Transfer transfer)
{
System.out.println(transfer.actualLength() + " bytes received !!!! ");
// write(handle, CONNECT_BODY, bodySent);
// LibUsb.freeTransfer(transfer);
}
};
// This callback is called after the ADB CONNECT message header is
// sent and sends the ADB CONNECT message body.
final TransferCallback sendData = new TransferCallback()
{
@Override
public void processTransfer(Transfer transfer)
{
System.out.println("send command to device");
// write(handle, CONNECT_BODY, bodySent);
// LibUsb.freeTransfer(transfer);
}
};
回复如下:
> Thermometre Pearl NC-7004 detecté !
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
18 bytes sent
--- DEVICE DESCRIPTOR ---
1201 1001 0000 0008 4119 2180 0001 0000 0001
9 bytes sent
--- CONFIGURATION DESCRIPTOR ---
0902 2200 0101 0080 32
4 bytes sent
--- DESCRIPTOR STRING ---
0403 0904 0000 0000
tentative de communication de la requete de données ...
doing interrupt transfer to device
Resultat du transfert :
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
java.lang.IllegalStateException: deviceHandlePointer is not initialized
at org.usb4java.LibUsb.attachKernelDriver(Native Method)
at usbDriver.Communication2.terminerCom(Communication2.java:313)
at usbDriver.usbDriver.main(usbDriver.java:37)
您能否就如何执行此操作向我提供建议?
答案 1 :(得分:1)
尽管这种异步数据传输仍有很多测试。我完全确定我的要求是好的。好消息是处理LibUsb.handleEventTimeOut中断传输的回调函数被调用...当超时到达时....
这很令人费解,因为在带有driverWizard的windows上使用的命令工作得很好。另外我认为应该可以使用LibUsb在Raspberry上进行当前配置,因为与设备的同步传输(获取描述符,配置...)工作正常。即使从未调用控制回调(可能因为设备在控制管道上没有发回任何内容),它也会以带有良好命令的TIMEOUT结束,而它是错误9&#34;命令无效&#34;命令略有不同......我认为这是一个好兆头,它表明设备至少对命令做出了一点反应。
但我害怕失去理智。这可能是:
我现在就打开每一个想法!我下周还会尝试一些尝试,但如果它不起作用,我会忘记这个特定的温度计。
那么你知道温度计/湿度计可以在树莓上轻松配置并允许实时(每分钟)测量和数据传输吗?
答案 2 :(得分:1)
实际上,这段代码确实有效!
private void baseRequest(){
LibUsb.clearHalt(handle, (byte)0x0);
LibUsb.clearHalt(handle, (byte)0x81);
int result;
int count = 0;
bufferData = ByteBuffer.allocateDirect(32);
Transfer interruptTransfer = LibUsb.allocTransfer(0);
LibUsb.fillInterruptTransfer(interruptTransfer , handle, ENDPOINT_ID, bufferData,receiveBaseRequest, null, 200L);
//bufferData.rewind();
LibUsb.unlockEvents(contexte);
LibUsb.submitTransfer(interruptTransfer);
bufferControl= ByteBuffer.allocateDirect(16);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
// now the data
bufferControl.put((byte)0xa1);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x20);
bufferControl.put((byte)0xa1);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x20);
bufferControl.rewind();
Transfer controlTransfer = LibUsb.allocTransfer(0);
//bufferControl.rewind();
LibUsb.fillControlSetup(bufferControl,(byte)0x21,(byte)0x09,( short)0x0200,(short)0x0000,(short)0x08);
LibUsb.fillControlTransfer(controlTransfer, handle, bufferControl,sendBaseRequest, null, 200L);
//bufferControl.rewind();
controlTransfer.setEndpoint((byte)0x00);
display(byteBuffer2String(controlTransfer.buffer()));
result = LibUsb.submitTransfer(controlTransfer);
// TODO : voir pour free les transferts
}
@Dryman:谢谢您的建议,我认为我的主要错误是在 fillControlSetup 之前执行 fillControlTransfer 。实际上, fillControlSetup 必须在 fillControlTransfer 之前完成(我注意到读取了synchronousControlTransfer的源代码)。无论如何,现在我可以与设备进行有效沟通,感谢您的建议!
答案 3 :(得分:0)
我认为它看起来应该更像这样:
ByteBuffer bufferControl= ByteBuffer.allocateDirect(16);
// leaving out 8 byte for setup packet
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
// now the data
bufferControl.put((byte)0xA1);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x20);
bufferControl.put((byte)0xA1);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x00);
bufferControl.put((byte)0x20);
bufferControl.rewind();
// this is for the data to read
ByteBuffer bufferData = ByteBuffer.allocateDirect(32);
Transfer controlTransfer = LibUsb.allocTransfer(0);
LibUsb.fillControlSetup(bufferControl,(byte)0x21,(byte)0x09, short)0x0200,(short)0x0,(short)0x08);
LibUsb.fillControlTransfer(controlTransfer, handle, bufferControl, sendData, null, 2000L);
int result = LibUsb.submitTransfer(controlTransfer);
if (result != LibUsb.SUCCESS)
{
throw new LibUsbException("Unable to submit control transfer", result);
}
System.out.println("doing interrupt transfer to device");
Transfer interruptTransfer = LibUsb.allocTransfer(0);
LibUsb.fillInterruptTransfer(interruptTransfer , handle, ENDPOINT_ID, bufferData,
receiveData, null, 3000L);
int result = LibUsb.submitTransfer(interruptTransfer);
if (result != LibUsb.SUCCESS)
{
throw new LibUsbException("Unable to submit interrupt transfer", result);
}
Thread.Sleep(5000);
答案 4 :(得分:0)
经过多次测试和变化后,它仍无法正常工作......
没有调用回调函数真的很烦人。 在提交controlTransfer时,应该调用sendData回调函数,不是吗?但在测试中,它从未被调用过。控制转移真的完成了吗?神秘......
另外,如果我说得好,那么USB中就没有真正的听众。设备只有在被要求时才能通话。这意味着一旦控制传输完成,我应该在我的数据端点0x81上执行中断传输,数据缓冲区为32字节,但我如何指定设备发回数据呢?我读到了方向标记,所以中断数据的第一个字节应该有一个特定的值,表明设备有效地写入这个缓冲区并发回数据?