首页 文章

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

提问于
浏览
1

我正在尝试使用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

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

    不,我想处理主要目标:从温度计中检索数据 . 使用嗅探工具,我看到我必须通过控制管道发送一个8字节变量的设置包 . 然后在 endpoints 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

    尽管这种异步数据传输仍有很多测试 . 我完全相信我的要求很好 . 好消息是处理LibUsb.handleEventTimeOut中断传输的回调函数被调用...当它的超时到达时....

    这很令人费解,因为在带有driverWizard的windows上使用的命令工作得很好 . 另外我认为应该可以使用LibUsb在Raspberry上进行当前配置,因为与设备的同步传输(获取描述符,配置...)工作正常 . 即使从未调用控件回调(可能因为设备在控制管道上没有发回任何内容),它以一个带有良好命令的TIMEOUT结束,而它是一个错误9“无效命令”,命令略有不同......它是一个好的迹象我认为,它表明设备至少对命令做出了一点反应 .

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

    • 由于LibUsb / Raspberry导致异步传输不可操作的不兼容性?我不喜欢覆盆子! )

    • LibUsb处理异步传输的方式有问题吗?如果设备对命令做出一点反应,它应该在管道0x81中写入触发中断传输完成事件,不是吗?那个's exactly what is dne with the pipe listening in DriverWizard even though i don'知道它是如何完成的 .

    我下周还会尝试一些尝试,但如果它没有't work i'我会忘记这个特殊的温度计 .
    那么你知道温度计/湿度计可以在树莓上轻松配置并允许实时(每分钟)测量和数据传输吗?

  • 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的源代码) . 无论如何,现在我可以与设备进行有效沟通,感谢您的建议!

  • 1

    我认为它看起来应该更像这样:

    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);
    
  • 0

    经过多次测试和变化后,它仍然不起作用......

    回调函数没有被调用真的很烦人 . 在提交controlTransfer时,应该调用sendData回调函数,不是吗?但在测试中,它从未被调用过 . 控制转移真的完成了吗?神秘......

    此外,如果我做得好,USB中没有真正的听众 . 设备只有在被要求时才能说话 . 这意味着一旦控制传输完成,我应该在我的数据 endpoints 0x81上执行中断传输,数据缓冲区为32字节,但我究竟能指定设备发回数据呢?我读到了方向标记,所以是数据的第一个字节中断应该有一个特定的值,表明设备有效地写在这个缓冲区并发回数据?

相关问题