Android O连接USB3.0接口的外设

新手上路,请多包涵

下面的流程在非Android O系统版本的手机中运行正常,在Android O连接USB2.0时也运行正常,仅在Android O连接USB3.0/3.1时,第一个指令的发送接收也正常, 然而第二个指令发送就失败了, 返回-1, 尝试过把发送时的bulkTransfer方法的第三个参数(即数据长度)修改为EndPoint的MaXPacketSize, 接收时的bulkTransfer方法的第三个参数修改为接收到数据的大小, 在我的使用中为0x0c, 这样第二个指令就可以正常发送接收, 但是第三个指令还是会发送失败, 可能跟这个有关, 但是最多就发送成功了两个指令

寻找USB设备

    val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
    //this method just filter the vendorId of device
    val dev = lookupCompatibleDevice(usbManager) ?: return

申请权限

    if (usbManager.hasPermission(dev)){
        //if has permission already
        connect(context, dev)
    }else {
        //request permission and connect device in receiver
        registerPermissionReceiver(context)
        val mPermissionIntent = PendingIntent.getBroadcast(context, 0, Intent(
                ACTION_USB_PERMISSION), 0)
        usbManager.requestPermission(dev, mPermissionIntent)
    }

获取EndPoint

fun connect(context: Context, device: UsbDevice){
    val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
    var intf : UsbInterface? = null
    (0 until (device.interfaceCount)).forEach {
        val i = device.getInterface(it)
        if (i.interfaceClass == UsbConstants.USB_CLASS_STILL_IMAGE){
            intf = i
        }
    }
    if (intf == null){
        //PTP interface not found
        connectListener.onConnectStateChange(ConnectState.NO_PTP_INTERFACE)
        return
    }

    if (device.interfaceCount > 1){
        connectListener.onConnectStateChange(ConnectState.MULTI_INTERFACE)
        return
    }

    val conn = usbManager.openDevice(device) ?: return
    if (conn.claimInterface(intf, true)){
        Log.i(TAG, "claim interface successful")
    }else {
        Log.i(TAG, "claim interface failure")
    }
    var bulkIn: UsbEndpoint? = null
    var bulkOut: UsbEndpoint? = null

    (0 until (intf!!.endpointCount)).forEach {
        val endpoint = intf!!.getEndpoint(it)
        Log.d(TAG, "connect: endpoint type: " + endpoint.type + "direction: " + endpoint.direction)
        if (endpoint.type == UsbConstants.USB_ENDPOINT_XFER_BULK) {
            if (endpoint.direction == UsbConstants.USB_DIR_IN) {
                bulkIn = endpoint
            } else if (endpoint.direction == UsbConstants.USB_DIR_OUT) {
                bulkOut = endpoint
            }
        }
    }
    if (bulkIn == null || bulkOut == null) {
        //
        connectListener.onConnectStateChange(ConnectState.BULK_NOT_ENOUGH)
        return
    }
    if (AppConfig.LOG) {
        Log.i(TAG, "Found compatible USB interface")
        Log.i(TAG, "Interface class " + intf?.interfaceClass)
        Log.i(TAG, "Interface subclass " + intf?.interfaceSubclass)
        Log.i(TAG, "Interface protocol " + intf?.interfaceProtocol)
        Log.i(TAG, "Bulk out max size " + bulkOut?.maxPacketSize)
        Log.i(TAG, "Bulk in max size " + bulkIn?.maxPacketSize)
    }
    val connection = UsbConnection(context.applicationContext, device.vendorId, conn, bulkOut!!, bulkIn!!, object : Connection.ConnectStateListener {
        override fun onConnectStateChange(state: ConnectState) {
            connectListener.onConnectStateChange(state)
            if (state.state < ConnectState.WIFI_ACKNOWLEDGED.state){
              
                CameraHolder.disconnectCamera(context)
            }
        }
    })

    when(device.vendorId){
        CanonVendorId -> { camera = CanonCamera(context, connection, cameraListener) }
        NikonVendorId -> { camera = NikonCamera(context, connection, cameraListener) }
        SonyVendorId -> { camera = SonyCamera(context, connection, cameraListener) }
        else -> { camera = Camera(context, connection, cameraListener) }
    }
    connectListener.onConnectStateChange(ConnectState.USB_CONNECTED)
}

the UsbConnection class just pack the EndPoints

发送指令

fun send(): Int {
    if (AppConfig.LOG_PACKETS){
        PacketUtil.logHexdump(TAG, byteBuffer.array(), byteBuffer.position(), byteBuffer.limit())
    }
    val res = connection.bulkTransfer(bulkOut, byteBuffer.array(), byteBuffer.limit(), timeout)
    return res
}

the bytebuffer contains the data that needs to be send

接收指令

res = connection.bulkTransfer(bulkIn, `in`.array(), maxPacketSize, AppConfig.USB_TRANSFER_TIMEOUT)

Any help will be appreciated..

阅读 3.4k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏