控制传输期间出现USB错误9

时间:2016-10-25 13:28:14

标签: linux libusb libusb-1.0

我正在尝试使用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请求的代码,我很乐意对其进行测试!

5 个答案:

答案 0 :(得分:1)

实际上我设法在我的设备上运行第一个请求!这只是发送请求的一个问题,这是不准确的。

不,我想处理主要目标:从温度计中检索数据。使用嗅探工具,我看到我必须通过控制管道发送一个设置包+8个字节的变量。然后在端点0x81上,器件应在中断模式下发回4 * 8字节的数据。我用原型工具测试了它:

screen of data request

当我不明白时,我应该做同步转移。我现在尝试了以下代码但没有成功。

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;命令略有不同......我认为这是一个好兆头,它表明设备至少对命令做出了一点反应。

但我害怕失去理智。这可能是:

  • 由于LibUsb / Raspberry导致异步传输不可操作的不兼容性?我不知道raspberry usb功能是否包含异步传输(但似乎很可能,因为没有它,很多设备都无法使用覆盆子!)
  • LibUsb处理异步传输的方式有问题吗?如果设备对命令做出一点反应,它应该在管道0x81中写入触发中断传输完成事件,不是吗?即使我不知道它是如何完成的,但这正是管道向导中管道的问题。

我现在就打开每一个想法!我下周还会尝试一些尝试,但如果它不起作用,我会忘记这个特定的温度计。
那么你知道温度计/湿度计可以在树莓上轻松配置并允许实时(每分钟)测量和数据传输吗?

答案 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字节,但我如何指定设备发回数据呢?我读到了方向标记,所以中断数据的第一个字节应该有一个特定的值,表明设备有效地写入这个缓冲区并发回数据?