2013-11-01 258 views
48

我試圖從主機模式下連接到我的Android手機的USB設備中獲取一些數據。我能夠將數據發送給它,但讀取失敗。Android USB主機從設備讀取

我已經看過severalexamples盡我所能,但我沒有任何USB通信的經驗,雖然現在我知道了一點,而且我一直在堅持這一點,我不想承認。

我對端點配置不是很熟悉,但我知道我的設備使用CDC類型的通信方法,並且輸出(從電話到設備)和輸入都被註冊。

下面是整個班級管理與連接到手機的唯一設備的USB連接,但沒有完成任何手段,但我希望在進一步學習之前讓閱讀部分工作。

public class UsbCommunicationManager 
{ 
    static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; 

    UsbManager usbManager; 
    UsbDevice usbDevice; 
    UsbInterface intf = null; 
    UsbEndpoint input, output; 
    UsbDeviceConnection connection; 

    PendingIntent permissionIntent; 

    Context context; 

    byte[] readBytes = new byte[64]; 

    public UsbCommunicationManager(Context context) 
    { 
     this.context = context; 
     usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); 

     // ask permission from user to use the usb device 
     permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); 
     IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); 
     context.registerReceiver(usbReceiver, filter); 
    } 

    public void connect() 
    { 
     // check if there's a connected usb device 
     if(usbManager.getDeviceList().isEmpty()) 
     { 
      Log.d("trebla", "No connected devices"); 
      return; 
     } 

     // get the first (only) connected device 
     usbDevice = usbManager.getDeviceList().values().iterator().next(); 

     // user must approve of connection 
     usbManager.requestPermission(usbDevice, permissionIntent); 
    } 

    public void stop() 
    { 
     context.unregisterReceiver(usbReceiver); 
    } 

    public String send(String data) 
    { 
     if(usbDevice == null) 
     { 
      return "no usb device selected"; 
     } 

     int sentBytes = 0; 
     if(!data.equals("")) 
     { 
      synchronized(this) 
      { 
       // send data to usb device 
       byte[] bytes = data.getBytes(); 
       sentBytes = connection.bulkTransfer(output, bytes, bytes.length, 1000); 
      } 
     } 

     return Integer.toString(sentBytes); 
    } 

    public String read() 
    { 
     // reinitialize read value byte array 
     Arrays.fill(readBytes, (byte) 0); 

     // wait for some data from the mcu 
     int recvBytes = connection.bulkTransfer(input, readBytes, readBytes.length, 3000); 

     if(recvBytes > 0) 
     { 
      Log.d("trebla", "Got some data: " + new String(readBytes)); 
     } 
     else 
     { 
      Log.d("trebla", "Did not get any data: " + recvBytes); 
     } 

     return Integer.toString(recvBytes); 
    } 

    public String listUsbDevices() 
    { 
     HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList(); 

     if(deviceList.size() == 0) 
     { 
      return "no usb devices found"; 
     } 

     Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); 
     String returnValue = ""; 
     UsbInterface usbInterface; 

     while(deviceIterator.hasNext()) 
     { 
      UsbDevice device = deviceIterator.next(); 
      returnValue += "Name: " + device.getDeviceName(); 
      returnValue += "\nID: " + device.getDeviceId(); 
      returnValue += "\nProtocol: " + device.getDeviceProtocol(); 
      returnValue += "\nClass: " + device.getDeviceClass(); 
      returnValue += "\nSubclass: " + device.getDeviceSubclass(); 
      returnValue += "\nProduct ID: " + device.getProductId(); 
      returnValue += "\nVendor ID: " + device.getVendorId(); 
      returnValue += "\nInterface count: " + device.getInterfaceCount(); 

      for(int i = 0; i < device.getInterfaceCount(); i++) 
      { 
       usbInterface = device.getInterface(i); 
       returnValue += "\n Interface " + i; 
       returnValue += "\n\tInterface ID: " + usbInterface.getId(); 
       returnValue += "\n\tClass: " + usbInterface.getInterfaceClass(); 
       returnValue += "\n\tProtocol: " + usbInterface.getInterfaceProtocol(); 
       returnValue += "\n\tSubclass: " + usbInterface.getInterfaceSubclass(); 
       returnValue += "\n\tEndpoint count: " + usbInterface.getEndpointCount(); 

       for(int j = 0; j < usbInterface.getEndpointCount(); j++) 
       { 
        returnValue += "\n\t Endpoint " + j; 
        returnValue += "\n\t\tAddress: " + usbInterface.getEndpoint(j).getAddress(); 
        returnValue += "\n\t\tAttributes: " + usbInterface.getEndpoint(j).getAttributes(); 
        returnValue += "\n\t\tDirection: " + usbInterface.getEndpoint(j).getDirection(); 
        returnValue += "\n\t\tNumber: " + usbInterface.getEndpoint(j).getEndpointNumber(); 
        returnValue += "\n\t\tInterval: " + usbInterface.getEndpoint(j).getInterval(); 
        returnValue += "\n\t\tType: " + usbInterface.getEndpoint(j).getType(); 
        returnValue += "\n\t\tMax packet size: " + usbInterface.getEndpoint(j).getMaxPacketSize(); 
       } 
      } 
     } 

     return returnValue; 
    } 

    private void setupConnection() 
    { 
     // find the right interface 
     for(int i = 0; i < usbDevice.getInterfaceCount(); i++) 
     { 
      // communications device class (CDC) type device 
      if(usbDevice.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) 
      { 
       intf = usbDevice.getInterface(i); 

       // find the endpoints 
       for(int j = 0; j < intf.getEndpointCount(); j++) 
       { 
        if(intf.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_OUT && intf.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) 
        { 
         // from android to device 
         output = intf.getEndpoint(j); 
        } 

        if(intf.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_IN && intf.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) 
        { 
         // from device to android 
         input = intf.getEndpoint(j); 
        } 
       } 
      } 
     } 
    } 

    private final BroadcastReceiver usbReceiver = new BroadcastReceiver() 
    { 
     public void onReceive(Context context, Intent intent) 
     { 
      String action = intent.getAction(); 
      if(ACTION_USB_PERMISSION.equals(action)) 
      { 
       // broadcast is like an interrupt and works asynchronously with the class, it must be synced just in case 
       synchronized(this) 
       { 
        if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) 
        { 
         setupConnection(); 

         connection = usbManager.openDevice(usbDevice); 
         connection.claimInterface(intf, true); 

         // set flow control to 8N1 at 9600 baud 
         int baudRate = 9600; 
         byte stopBitsByte = 1; 
         byte parityBitesByte = 0; 
         byte dataBits = 8; 
         byte[] msg = { 
          (byte) (baudRate & 0xff), 
          (byte) ((baudRate >> 8) & 0xff), 
          (byte) ((baudRate >> 16) & 0xff), 
          (byte) ((baudRate >> 24) & 0xff), 
          stopBitsByte, 
          parityBitesByte, 
          (byte) dataBits 
         }; 

         connection.controlTransfer(UsbConstants.USB_TYPE_CLASS | 0x01, 0x20, 0, 0, msg, msg.length, 5000); 
        } 
        else 
        { 
         Log.d("trebla", "Permission denied for USB device"); 
        } 
       } 
      } 
      else if(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) 
      { 
       Log.d("trebla", "USB device detached"); 
      } 
     } 
    }; 
} 

我一直從read()方法,它表明了某種錯誤,它總是超時越來越-1。也許問題來自連接配置,我試了幾次(閱讀:試用和錯誤),沒有工作,令人驚訝的是我不需要任何配置發送數據到設備。


編輯

還必須指出的是,我使用的電纜微型USB到微型USB,它只有一條出路的作品,這是我的設備是由我的動力手機只有當插頭A連接到手機和插頭B連接到設備,而不是反過來......這似乎很奇怪。事實上,我能夠發送數據,但沒有收到時插入正確的方式仍然存在。


EDIT 2

我發現somebody else had the same problem但他似乎沒能解決這個問題。


EDIT 3

我終於找到上this page溶液:

另一個主要的監督是,沒有機制爲主機,以通知該設備有一個數據在主機側的接收器準備接受數據。這意味着設備可能會嘗試在主機未偵聽時發送數據,從而導致傳輸例程中的冗長阻塞超時。因此強烈建議在可能的情況下使用虛擬串行線路DTR(數據終端就緒)信號來確定主機應用程序是否準備好數據。

所以DTR信號是強制性的,所有我所要做的就是把它添加到接口配置:

connection.controlTransfer(0x21, 0x22, 0x1, 0, null, 0, 0); 

EDIT 4

如果有人有興趣我完成了這個項目,它是open source and published on my GitHub account。但它始終不穩定(請參閱notes),我不打算繼續使用它,但它很有用。隨意使用它爲您自己的項目。

+0

您所使用的USB設備?我想發送數據來設置我的CP2112EK設備的GPIO引腳。你可以幫我關於這個 –

+1

我使用的是一個ATmega32U4,本質上是一個Arduino Leonardo,它自己註冊爲一個CDC設備。您的[CP2112EK](http://www.silabs.com/products/interface/Pages/CP2112EK.aspx)似乎是需要其他配置的HID設備。 – Solenoid

+0

@Solenoid放置此行的位置.. controlTransfer(0x21,0x22,0x1,0,null,0,0)?? –

回答

1

您可以從https://github.com/mik3y/usb-serial-for-android

我的示例代碼中使用UsbSerial庫的:

UsbManager usbManager = null; 
    UsbDeviceConnection connection = null; 
    UsbSerialDriver driver = null; 
    UsbSerialPort port = null; 

    usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); 

    List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); 
    // Open a connection to the first available driver. 

    for (UsbSerialDriver usd : availableDrivers) { 
     UsbDevice udv = usd.getDevice(); 
     if (udv.getVendorId()==0x067B || udv.getProductId()==2303){ 
      driver = usd; 
      break; 
     } 
    } 
     connection = usbManager.openDevice(driver.getDevice()); 

     port = driver.getPorts().get(0); 

     driver.getDevice(). 

    } 

     if (connection == null) return; 

     try{ 

      port.open(connection); 
      port.setParameters(4800, UsbSerialPort.DATABITS_8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); 

       try{ 

        byte buffer[] = new byte[250]; 
        //Log.d("GPS_REQ", "->"); 
        int numBytesRead = port.read(buffer, 500); //5000; 

       }catch (Exception e) { 
        Log.d("GPS_ERR", e.getLocalizedMessage()); 
       } 
相關問題