title: USB error 9 during control transfer
body: <p>I'm trying to make a little driver to communicate with an USB thermometer, using java library Libusb (org.usb4java.LibUsb). I'm testing it on a Raspeberry Pi (3b) with vanilla linux-arm. </p>
  
  <p>My problem is that I don't succeed in transferring a control transfer to the device. I get the error:</p>
  
  <blockquote>
    <p>org.usb4java.LibUsbException: USB error 9: Control transfer failed: Pipe error</p>
  </blockquote>
  
  <p>Here is my code:</p>
  
  <p>Main class:</p>
  
  <pre class="lang-java prettyprint-override"><code>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();
          }
      }
  }
  </code></pre>
  
  <p>Communication2 class: </p>
  
  <pre class="lang-java prettyprint-override"><code>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 &lt; 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 &lt; 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 &lt; 0)
              {
                  throw new LibUsbException(
                      "Unable to read device descriptor", result);
              }
              if (descriptor.idVendor() == VENDOR_ID &amp;&amp; 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 &amp;&amp; (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 &lt; 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&lt;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;
          }
      }
  }
  </code></pre>
  
  <p>The error occurs when I call <code>LibUsb.ControlTransfer()</code>, trying to transfer a <code>GET_DESCRIPTOR</code> control packet. Here is the complete return of the code with device descriptor info: </p>
  
  <pre><code>&gt; 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) 
  </code></pre>
  
  <p>I think the pipe is well initialized (Handle seems ok, interface was successfully claimed too). Also the Libusb doc indicates : </p>
  
  <blockquote>
    <p><code>LIBUSB_ERROR_PIPE</code> if the control request was not supported by the
    device</p>
  </blockquote>
  
  <p>So I guess I'm just misdoing the control request. If you know the code to send a <code>GET_DESCRIPTOR</code> request properly I'd be glad to test it! </p>