Android USB主机从设备读取

我试图从连接到主机模式的Android手机的USB设备中获取一些数据。 我能够发送数据,但读取失败。

我已经看过几个 例子 ,尽我所能,但我没有任何的USB通信经验,虽然现在我知道了一些,我一直坚持这一点,我不愿意承认。

我对端点configuration不是很熟悉,但是我知道我的设备使用CDCtypes的通信方法,并且输出(从电话到设备)和input都被注册。

这是全class人员用连接到手机上的唯一设备来pipe理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 ,它指出某种错误,它总是超时。 也许问题来自连接configuration,我已经尝试了几个(阅读:试验和错误),没有工作,令人惊讶的是我不需要任何configuration发送数据到设备。


编辑

还必须注意的是,我使用的电缆是micro-USB到micro-USB,它只能以一种方式工作,也就是说,只有当插头A连接到电话和插头B连接到设备,而不是其他的方式…这似乎很奇怪。 事实上,我能够发送数据,而不是正确插入时仍然收到。


编辑2

我发现别人有同样的问题,但似乎无法解决这个问题。


编辑3

我终于在这个页面上find了解决scheme:

另一个主要的疏漏是主机没有任何机制通知设备主机端有数据接收器可以接收数据。 这意味着设备可能会尝试发送数据,而主机没有监听,从而导致传输例程中冗长的阻塞超时。 因此强烈build议在可能的情况下使用虚拟串行线路DTR(数据terminal就绪)信号来确定主机应用程序是否准备好数据。

所以DTR信号是强制性的,我所要做的只是将其添加到接口configuration中:

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

编辑4

如果有人感兴趣,我完成了项目,它是开源的,并在我的GitHub帐户上发布 。 虽然它一直不稳定(见注释 ),我不打算继续工作,但它的工作原理。 随意使用它为您自己的项目。

你可以使用从https://github.com/mik3y/usb-serial-for-android的; UsbSerial Lib

我的示例代码:

  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()); }