2014-02-06 160 views
0

我'能够连接到设备,并要求设备规格:无法读取USB数据在主机模式与Android HID设备

规格:

Model: /dev/bus/usb/001/002 
ID: 1002 
Class: 0 
Protocol: 0 
Vendor ID 1155 
Product ID: 22352 
Interface count: 1 
--------------------------------------- 
*****  ***** 
Interface index: 0 
Interface ID: 0 
Inteface class: 3 USB_CLASS_HID 
Interface protocol: 0 
Endpoint count: 2 
++++ ++++ ++++ 
Endpoint index: 0 
Attributes: 3 
Direction: 128 (device to host) 
Number: 1 
Interval: 1 
Packet size: 64 
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint) 
++++ ++++ ++++ 
Endpoint index: 1 
Attributes: 3 
Direction: 0 (host to device) 
Number: 1 
Interval: 1 
Packet size: 64 
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint) 
No more devices connected. 

我'也能发送数据从主机到设备,使用这种方法:

int bufferDataLength = mEndpointOut.getMaxPacketSize(); 
    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1); 
    UsbRequest request = new UsbRequest(); 

    buffer.put(DataToSend); 

    request.initialize(mDeviceConnection, mEndpointOut); 
    request.queue(buffer, bufferDataLength); 
    try 
    { 
     if (request.equals(mDeviceConnection.requestWait())) 
     { 
      // Read an analyze the incoming data here 
      byte[] byteBuffer = new byte[buffer.remaining()]; 
      buffer.get(byteBuffer, 0, buffer.remaining()); 
      return true; 
     } 
    } 
    catch (Exception ex) 
    { 
     Log.e(TAG, "Error sending data: " + ex.toString()); 
    } 
    return false; 

但我'不能从设备读取,我已经测试了几种方法都没有成功..

例如这不起作用:

int bufferDataLength = mEndpointIn.getMaxPacketSize(); 
    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1); 

    //Make a request 
    UsbRequest request = new UsbRequest(); 
    request.initialize(mDeviceConnection, mEndpointIn); 
    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength); 
    //For IN endpoints, data is read into the buffer 
    request.queue(buffer, bufferDataLength); 
    //This blocks until the request is successful 
    //Make sure the request that finished is the one you need 
    if (mDeviceConnection.requestWait() == request) { 
    // Read an analyze the incoming data here 
     byte[] byteBuffer = new byte[buffer.remaining()]; 
     buffer.get(byteBuffer, 0, buffer.remaining()); 
    } 

建议?

+0

您是否使用了正确的终点? In Request对我来说很好 – Sai

+0

是的,我认为这是正确的终点,无论如何,这是一个终点,但我没有运气.. – andrepaso

+0

你如何轮询In Endpoint的新消息?你能分享读线程吗?你有没有提到Android SDK中的USB Missile Launcher示例? – Sai

回答

0

我使用这个类,解决了我的问题,我回答我的问题,我希望它可以帮助别人:

/** 
* This class is used for talking to hid of the dongle, connecting, disconnencting and enumerating the devices. 
* @author gai 
*/ 
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 
public class HidBridge { 
    private Context _context; 
    private int _productId; 
    private int _vendorId; 


    //private HidBridgeLogSupporter _logSupporter = new HidBridgeLogSupporter(); 
    private static final String ACTION_USB_PERMISSION = 
      "com.example.company.app.testhid.USB_PERMISSION"; 

    // Locker object that is responsible for locking read/write thread. 
    private final Object _locker = new Object(); 
    private Thread _readingThread = null; 
    private boolean _runReadingThread = false; 
    private String _deviceName; 

    private UsbManager _usbManager; 
    private UsbDevice _usbDevice; 

    // The queue that contains the read data. 
    private Queue<byte[]> _receivedQueue; 

    /** 
    * Creates a hid bridge to the dongle. Should be created once. 
    * @param context is the UI context of Android. 
    * @param productId of the device. 
    * @param vendorId of the device. 
    */ 
    public HidBridge(Context context, int productId, int vendorId) { 
     _context = context; 
     _productId = productId; 
     _vendorId = vendorId; 
     _receivedQueue = new LinkedList<byte[]>(); 
    } 

    /** 
    * Searches for the device and opens it if successful 
    * @return true, if connection was successful 
    */ 
    public boolean OpenDevice() { 
     _usbManager = (UsbManager) _context.getSystemService(Context.USB_SERVICE); 

     HashMap<String, UsbDevice> deviceList = _usbManager.getDeviceList(); 

     Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); 
     _usbDevice = null; 

     // Iterate all the available devices and find ours. 
     while(deviceIterator.hasNext()){ 
      UsbDevice device = deviceIterator.next(); 
      if (device.getProductId() == _productId && device.getVendorId() == _vendorId) { 
       _usbDevice = device; 
       _deviceName = _usbDevice.getDeviceName(); 
      } 
     } 

     if (_usbDevice == null) { 
      Log("Cannot find the device. Did you forgot to plug it?"); 
      Log(String.format("\t I search for VendorId: %s and ProductId: %s", _vendorId, _productId)); 
      return false; 
     } 

     // Create and intent and request a permission. 
     PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0); 
     IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); 
     _context.registerReceiver(mUsbReceiver, filter); 

     _usbManager.requestPermission(_usbDevice, mPermissionIntent); 
     Log("Found the device"); 
     return true; 
    } 

    /** 
    * Closes the reading thread of the device. 
    */ 
    public void CloseTheDevice() { 
     try 
     { 
      StopReadingThread(); 
      _context.unregisterReceiver(mUsbReceiver); 
     } 
     catch(RuntimeException e) 
     { 
      Log("Error happend while closing device. Usb reciver not connected."); 
     } 
    } 

    /** 
    * Starts the thread that continuously reads the data from the device. 
    * Should be called in order to be able to talk with the device. 
    */ 
    public void StartReadingThread() { 
     if (_readingThread == null) { 
      _runReadingThread = true; 
      _readingThread = new Thread(readerReceiver); 
      _readingThread.start(); 
     } else { 
      Log("Reading thread already started"); 
     } 
    } 

    /** 
    * Stops the thread that continuously reads the data from the device. 
    * If it is stopped - talking to the device would be impossible. 
    */ 
    public void StopReadingThread() { 
     if (_readingThread != null) { 
      // Just kill the thread. It is better to do that fast if we need that asap. 
      _runReadingThread = false; 
      _readingThread = null; 
     } else { 
      Log("No reading thread to stop"); 
     } 
    } 

    /** 
    * Write data to the usb hid. Data is written as-is, so calling method is responsible for adding header data. 
    * @param bytes is the data to be written. 
    * @return true if succeed. 
    */ 
    public boolean WriteData(byte[] bytes) { 
     try 
     { 
      // Lock that is common for read/write methods. 
      synchronized (_locker) { 
       UsbInterface writeIntf = _usbDevice.getInterface(0); 
       UsbEndpoint writeEp = writeIntf.getEndpoint(1); 
       UsbDeviceConnection writeConnection = _usbManager.openDevice(_usbDevice); 

       // Lock the usb interface. 
       writeConnection.claimInterface(writeIntf, true); 

       // Write the data as a bulk transfer with defined data length. 
       int r = writeConnection.bulkTransfer(writeEp, bytes, bytes.length, 0); 
       if (r != -1) { 
        Log(String.format("Written %s bytes to the dongle. Data written: %s", r, composeString(bytes))); 
       } else { 
        Log("Error happened while writing data. No ACK"); 
       } 

       // Release the usb interface. 
       writeConnection.releaseInterface(writeIntf); 
       writeConnection.close(); 
      } 

     } catch(NullPointerException e) 
     { 
      Log("Error happend while writing. Could not connect to the device or interface is busy?"); 
      Log.e("HidBridge", Log.getStackTraceString(e)); 
      return false; 
     } 
     return true; 
    } 

    /** 
    * @return true if there are any data in the queue to be read. 
    */ 
    public boolean IsThereAnyReceivedData() { 
     synchronized(_locker) { 
      return !_receivedQueue.isEmpty(); 
     } 
    } 

    /** 
    * Queue the data from the read queue. 
    * @return queued data. 
    */ 
    public byte[] GetReceivedDataFromQueue() { 
     synchronized(_locker) { 
      return _receivedQueue.poll(); 
     } 
    } 

    // The thread that continuously receives data from the dongle and put it to the queue. 
    private Runnable readerReceiver = new Runnable() { 
     public void run() { 
      if (_usbDevice == null) { 
       Log("No device to read from"); 
       return; 
      } 

      UsbEndpoint readEp; 
      UsbDeviceConnection readConnection = null; 
      UsbInterface readIntf = null; 
      boolean readerStartedMsgWasShown = false; 

      // We will continuously ask for the data from the device and store it in the queue. 
      while (_runReadingThread) { 
       // Lock that is common for read/write methods. 
       synchronized (_locker) { 
        try 
        { 
         if (_usbDevice == null) { 
          OpenDevice(); 
          Log("No device. Recheking in 10 sec..."); 

          Sleep(10000); 
          continue; 
         } 

         readIntf = _usbDevice.getInterface(0); 
         readEp = readIntf.getEndpoint(0); 
         if (!_usbManager.getDeviceList().containsKey(_deviceName)) { 
          Log("Failed to connect to the device. Retrying to acquire it."); 
          OpenDevice(); 
          if (!_usbManager.getDeviceList().containsKey(_deviceName)) { 
           Log("No device. Recheking in 10 sec..."); 

           Sleep(10000); 
           continue; 
          } 
         } 

         try 
         { 

          readConnection = _usbManager.openDevice(_usbDevice); 

          if (readConnection == null) { 
           Log("Cannot start reader because the user didn't gave me permissions or the device is not present. Retrying in 2 sec..."); 
           Sleep(2000); 
           continue; 
          } 

          // Claim and lock the interface in the android system. 
          readConnection.claimInterface(readIntf, true); 
         } 
         catch (SecurityException e) { 
          Log("Cannot start reader because the user didn't gave me permissions. Retrying in 2 sec..."); 

          Sleep(2000); 
          continue; 
         } 

         // Show the reader started message once. 
         if (!readerStartedMsgWasShown) { 
          Log("!!! Reader was started !!!"); 
          readerStartedMsgWasShown = true; 
         } 

         // Read the data as a bulk transfer with the size = MaxPacketSize 
         int packetSize = readEp.getMaxPacketSize(); 
         byte[] bytes = new byte[packetSize]; 
         int r = readConnection.bulkTransfer(readEp, bytes, packetSize, 50); 
         if (r >= 0) { 
          byte[] trancatedBytes = new byte[r - 1]; // Truncate bytes in the honor of r 

          int i=0; 
          for (byte b : bytes) { 
           if (i > 0) 
            trancatedBytes[i - 1] = b; 
           i++; 
          } 

          _receivedQueue.add(trancatedBytes); // Store received data 
          Log(String.format("Message received of lengths %s and content: %s", r, composeString(bytes))); 
         } 

         // Release the interface lock. 
         readConnection.releaseInterface(readIntf); 
         readConnection.close(); 
         } 

        catch (NullPointerException e) { 
         Log("Error happened while reading. No device or the connection is busy"); 
         Log.e("HidBridge", Log.getStackTraceString(e)); 
        } 
        catch (ThreadDeath e) { 
         if (readConnection != null) { 
          readConnection.releaseInterface(readIntf); 
          readConnection.close(); 
         } 

         throw e; 
        } 
       } 

       // Sleep for 10 ms to pause, so other thread can write data or anything. 
       // As both read and write data methods lock each other - they cannot be run in parallel. 
       // Looks like Android is not so smart in planning the threads, so we need to give it a small time 
       // to switch the thread context. 
       Sleep(10); 
      } 
     } 
    }; 

    private void Sleep(int milliseconds) { 
     try { 
      Thread.sleep(milliseconds); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 

     public void onReceive(Context context, Intent intent) { 
      String action = intent.getAction(); 
      if (ACTION_USB_PERMISSION.equals(action)) { 
       synchronized (this) { 
        UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 

        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 
         if(device != null){ 
          //call method to set up device communication 
         } 
        } 
        else { 
         Log.d("TAG", "permission denied for the device " + device); 
        } 
       } 
      } 
     } 
    }; 

    /** 
    * Logs the message from HidBridge. 
    * @param message to log. 
    */ 
    private void Log(String message) { 
     //LogHandler logHandler = LogHandler.getInstance(); 
     //logHandler.WriteMessage("HidBridge: " + message, LogHandler.GetNormalColor()); 
     Log.i("HidBridge: ", message); 
    } 

    /** 
    * Composes a string from byte array. 
    */ 
    private String composeString(byte[] bytes) { 
     StringBuilder builder = new StringBuilder(); 
     for (byte b: bytes) { 
      builder.append(b); 
      builder.append(" "); 
     } 

     return builder.toString(); 
    } 
}