Android O通过USB3.0电缆与DLSR相机通信

时间:2018-12-20 08:38:59

标签: android usb

当Android版本不是8。*。0或相机的usb电缆不是3.0时,这些代码可以很好地工作,但是当Android O达到usb3.0时,我只能向相机发送一个命令并收到一个回复发送第二条命令,send方法返回-1,这意味着发送失败。

查找设备

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

声明界面并获取端点

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

UsbConnection类仅包装端点

发送命令

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
}

字节缓冲区包含需要发送的数据

接收响应

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

我发现发送的数据大小是否是端点的最大数据包大小,我可以成功发送第二个命令,并且如果我读取的数据大小恰好等于响应的数据大小,那么我可以读取第二个响应成功,但是这在第三个命令中不起作用,当我发送第三个命令时,它总是失败

任何帮助将不胜感激。

0 个答案:

没有答案