java - Android接收USB批量传输

标签 java android usb transfer libusb

我创建了一个 Java 应用程序,它将自身设置为 USB 附件并通过批量传输发送一些数据。

Android 设备应该会看到这一点并将数据打印到 TextView。目前,我拥有它,以便 Android 设备可以看到配件的连接,并启动应用程序,批量传输但是失败,并出现以下错误。

org.usb4java.LibUsbException: USB error 5: Bulk write error!: Entity not found
    at com.xxx.xxx.AccessoryTest.writeAndRead(AccessoryTest.java:60)
    at com.xxx.xxx.AccessoryTest.main(AccessoryTest.java:37)

欢迎任何建议!

我有另一个实用程序,它将 Android 设备的端点信息报告为

  Endpoint Descriptor:
    bLength                  7
    bDescriptorType          5
    bEndpointAddress      0x81  EP 1 IN
    bmAttributes             2
      Transfer Type             Bulk
      Synch Type                None
      Usage Type                Data
    wMaxPacketSize         512
    bInterval                0
    extralen                 0
    extra:

  Endpoint Descriptor:
    bLength                  7
    bDescriptorType          5
    bEndpointAddress      0x02  EP 2 OUT
    bmAttributes             2
      Transfer Type             Bulk
      Synch Type                None
      Usage Type                Data
    wMaxPacketSize         512
    bInterval                0
    extralen                 0
    extra:

我正在尝试写入 0x02 端点

Android 代码

public class MainActivity extends AppCompatActivity implements Runnable {

    private UsbManager manager;
    private UsbAccessory accessory;
    private ParcelFileDescriptor accessoryFileDescriptor;
    private FileInputStream accessoryInput;
    private FileOutputStream accessoryOutput;

    private TextView questionTV;

    private final BroadcastReceiver usbBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
                synchronized (this) {
                    accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                }
            } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
                UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                if (accessory != null) {
                    // call your method that cleans up and closes communication with the accessory
                    try {
                        accessoryFileDescriptor.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        manager = (UsbManager) getSystemService(Context.USB_SERVICE);

        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
        registerReceiver(usbBroadcastReceiver, filter);

        if (getLastNonConfigurationInstance() != null)
        {
            accessory = (UsbAccessory) getLastNonConfigurationInstance();
            openAccessory();
        }

        setContentView(R.layout.activity_main);
    }

    private void openAccessory() {
        accessoryFileDescriptor = manager.openAccessory(accessory);
        if(accessoryFileDescriptor != null) {
            FileDescriptor fd = accessoryFileDescriptor.getFileDescriptor();
            accessoryInput = new FileInputStream(fd);
            accessoryOutput = new FileOutputStream(fd);
            Thread thread = new Thread(null, this, "AccessoryThread");
            thread.start();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void run() {
        int ret = 0;
        byte[] buffer = new byte[51];
        int bufferUsed = 0;

        while(ret >= 0) {
            try {
                ret = accessoryInput.read(buffer);
            } catch (IOException e) {
                Log.e("MainActivity", "Exception in USB accessory input reading", e);
                break;
            }
        }

        String question = new String(buffer);

        LinearLayout layout= (LinearLayout) findViewById(R.id.layout);

        questionTV = new TextView(this);
        questionTV.setText(question);

        layout.addView(questionTV);
    }
}

Java 应用程序代码

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import org.usb4java.BufferUtils;
import org.usb4java.Context;
import org.usb4java.Device;
import org.usb4java.DeviceDescriptor;
import org.usb4java.DeviceHandle;
import org.usb4java.DeviceList;
import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;

public class AccessoryTest {

    private final static byte REQUEST_TYPE_READ = (byte) 0xC0;
    private final static byte END_POINT_IN = (byte) 0x81;
    private final static byte END_POINT_OUT = (byte) 0x02;

    private final static short NEXUS7_VENDORID = (short) 0x18D1;
    private final static short NEXUS7_PRODUCTID = (short) 0x4EE1;

    private static Context context;
    private static Device device;
    private static DeviceHandle handle;

    public static void main(String[] args) {
        try {
            init();
            int result = setupAccessory("PCHost", "PCHost1", "Description", "1.0", "http://www.mycompany.com",
                    "SerialNumber");

            if (result != LibUsb.SUCCESS)
                throw new LibUsbException("Unable to setup Accessory", result);

            writeAndRead();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            LibUsb.releaseInterface(handle, 0);
            LibUsb.resetDevice(handle);
            LibUsb.close(handle);
            LibUsb.exit(context);
        }

    }

    private static void writeAndRead() {
        String question = "Hello Android I'll be your host today, how are you?";
        byte[] questionBuffer = question.getBytes();
        ByteBuffer questionData = BufferUtils.allocateByteBuffer(questionBuffer.length);
        IntBuffer transferred = IntBuffer.allocate(1);

        int result = 0;
        //THIS IS THE PART WHERE IT FAILS!
        result = LibUsb.bulkTransfer(handle, END_POINT_OUT, questionData, transferred, 5000);

        if(result < 0) {
            throw new LibUsbException("Bulk write error!", result);
        }
    }

    private static void init() {
        context = new Context();
        int result = LibUsb.init(context);
        if (result != LibUsb.SUCCESS)
            throw new LibUsbException("Unable to initialize libusb.", result);

        device = findDevice(NEXUS7_VENDORID);

        handle = new DeviceHandle();

        result = LibUsb.open(device, handle);
        if (result < 0)
            throw new LibUsbException("Unable to open USB device", result);

        result = LibUsb.claimInterface(handle, 0);
        if (result != LibUsb.SUCCESS)
            throw new LibUsbException("Unable to claim interface", result);
    }

    private static Device findDevice(short vendorId) {
        // Read the USB device list
        DeviceList list = new DeviceList();
        int result = LibUsb.getDeviceList(null, list);
        if (result < 0)
            throw new LibUsbException("Unable to get device list", result);

        try {
            // Iterate over all devices and scan for the right one
            for (Device device : list) {
                DeviceDescriptor descriptor = new DeviceDescriptor();
                result = LibUsb.getDeviceDescriptor(device, descriptor);
                if (result != LibUsb.SUCCESS)
                    throw new LibUsbException("Unable to read device descriptor", result);
                if (descriptor.idVendor() == vendorId)
                    return device;
            }
        } finally {
            // Ensure the allocated device list is freed
            LibUsb.freeDeviceList(list, true);
        }

        // Device not found
        return null;
    }

    private static int setupAccessory(String vendor, String model, String description, String version, String url,
            String serial) throws LibUsbException {

        int response = 0;

        // Setup setup token
        response = transferSetupPacket((short) 2, REQUEST_TYPE_READ, (byte) 51);

        // Setup data packet
        response = transferAccessoryDataPacket(vendor, (short) 0);
        response = transferAccessoryDataPacket(model, (short) 1);
        response = transferAccessoryDataPacket(description, (short) 2);
        response = transferAccessoryDataPacket(version, (short) 3);
        response = transferAccessoryDataPacket(url, (short) 4);
        response = transferAccessoryDataPacket(serial, (short) 5);

        // Setup handshake packet
        response = transferSetupPacket((short) 0, (byte) (LibUsb.REQUEST_TYPE_VENDOR | LibUsb.ENDPOINT_OUT), (byte) 53);

        LibUsb.releaseInterface(handle, 0);

        return response;
    }

    private static int transferSetupPacket(short bufferLength, byte requestType, byte request) throws LibUsbException {
        int response = 0;
        byte[] bytebuff = new byte[bufferLength];
        ByteBuffer data = BufferUtils.allocateByteBuffer(bytebuff.length);
        data.put(bytebuff);

        final short wValue = 0;
        final short wIndex = 0;
        final long timeout = 1000;

        data.rewind();
        response = LibUsb.controlTransfer(handle, requestType, request, wValue, wIndex,
                data, timeout);

        if(response < 0)
            throw new LibUsbException("Unable to transfer setup packet ", response);

        return response;
    }

    private static int transferAccessoryDataPacket(String param, short index) {
        int response;
        byte[] byteArray = param.getBytes();
        ByteBuffer data = BufferUtils.allocateByteBuffer(byteArray.length);
        data.put(byteArray);
        final byte bRequest = (byte) 52;
        final short wValue = 0;
        final long timeout = 0;
        response = LibUsb.controlTransfer(handle, LibUsb.REQUEST_TYPE_VENDOR, bRequest, wValue, index,
                data, timeout);
        if(response < 0)
            throw new LibUsbException("Unable to control transfer.", response);
        return response;
    }

}

AndroidManifest.xml

<uses-feature android:name="android.hardware.usb.accessory" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <uses-library android:name="com.android.future.usb.accessory" />
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
        </intent-filter>

        <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
            android:resource="@xml/accessory_filter" />
    </activity>
</application>

最佳答案

该问题是根据 AOP 标准,一旦 Android 设备进入 Accessory 模式,其 VID 和 PID 就会发生变化

因此,在设置配件后,需要回收设备句柄和接口(interface)。

关于java - Android接收USB批量传输,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32627760/

相关文章:

java - Jfreechart索引越界异常

java - 如何防止正则表达式转换 bbcode 超链接?

android - 自定义 ContentProvider 建议未显示

java - 在 WebView android 中单击链接时显示 pdf

java - Google 云端硬盘撤销共享文件的权限

java - 如何做一个字符串包含检查EL

android - 从 Assets 中加载包含带有 src 的 javascript 的 html 字符串

ubuntu - 安装在 USB 驱动器上的 ubuntu 上的 CUDA/OpenCL

java - "The crash happened outside the Java Virtual Machine in native code."如何解决这个错误(Java)?

c# - USB 如何创建可启动的自定义 USB 应用程序?