mirror of
https://github.com/mik3y/usb-serial-for-android
synced 2025-06-08 16:36:10 +00:00
Initial CDC ACM support.
Tested on Arduino Uno.
This commit is contained in:
parent
f801b31997
commit
b4b6d147ea
@ -2,4 +2,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
|
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
|
||||||
<usb-device vendor-id="1027" product-id="24577" />
|
<usb-device vendor-id="1027" product-id="24577" />
|
||||||
|
<!-- 0x2341 / 0x0001: Arduino Uno -->
|
||||||
|
<usb-device vendor-id="9025" product-id="1" />
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -0,0 +1,159 @@
|
|||||||
|
package com.hoho.android.usbserial.driver;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import android.hardware.usb.UsbConstants;
|
||||||
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
|
import android.hardware.usb.UsbEndpoint;
|
||||||
|
import android.hardware.usb.UsbInterface;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* USB CDC/ACM serial driver implementation.
|
||||||
|
*
|
||||||
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
|
*/
|
||||||
|
public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
|
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
|
||||||
|
|
||||||
|
private UsbDevice mDevice;
|
||||||
|
private UsbDeviceConnection mConnection;
|
||||||
|
private final byte[] mReadBuffer = new byte[4096];
|
||||||
|
|
||||||
|
private UsbInterface mControlInterface;
|
||||||
|
private UsbInterface mDataInterface;
|
||||||
|
|
||||||
|
private UsbEndpoint mControlEndpoint;
|
||||||
|
private UsbEndpoint mReadEndpoint;
|
||||||
|
private UsbEndpoint mWriteEndpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param usbDevice
|
||||||
|
* @param connection
|
||||||
|
*/
|
||||||
|
public CdcAcmSerialDriver(UsbDevice usbDevice, UsbDeviceConnection connection) {
|
||||||
|
mDevice = usbDevice;
|
||||||
|
mConnection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open() throws IOException {
|
||||||
|
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
|
||||||
|
|
||||||
|
Log.d(TAG, "Claiming control interface.");
|
||||||
|
mControlInterface = mDevice.getInterface(0);
|
||||||
|
Log.d(TAG, "Control iface=" + mControlInterface);
|
||||||
|
// class should be USB_CLASS_COMM
|
||||||
|
|
||||||
|
if (!mConnection.claimInterface(mControlInterface, true)) {
|
||||||
|
throw new IOException("Could not claim control interface.");
|
||||||
|
}
|
||||||
|
mControlEndpoint = mControlInterface.getEndpoint(0);
|
||||||
|
Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
|
||||||
|
|
||||||
|
Log.d(TAG, "Claiming data interface.");
|
||||||
|
mDataInterface = mDevice.getInterface(1);
|
||||||
|
Log.d(TAG, "data iface=" + mDataInterface);
|
||||||
|
// class should be USB_CLASS_CDC_DATA
|
||||||
|
|
||||||
|
if (!mConnection.claimInterface(mDataInterface, true)) {
|
||||||
|
throw new IOException("Could not claim data interface.");
|
||||||
|
}
|
||||||
|
mReadEndpoint = mDataInterface.getEndpoint(1);
|
||||||
|
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
|
||||||
|
mWriteEndpoint = mDataInterface.getEndpoint(0);
|
||||||
|
Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
|
||||||
|
|
||||||
|
Log.d(TAG, "Setting line coding");
|
||||||
|
setBaudRate(115200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int USB_RECIP_INTERFACE = 0x01;
|
||||||
|
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
|
||||||
|
|
||||||
|
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
|
||||||
|
|
||||||
|
private int sendAcmControlMessage(int request, int value, byte[] buf) {
|
||||||
|
return mConnection.controlTransfer(USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int setAcmLineCoding(int bitRate, int stopBits, int parity, int dataBits) {
|
||||||
|
byte[] msg = {
|
||||||
|
(byte) ( bitRate & 0xff),
|
||||||
|
(byte) ((bitRate >> 8 ) & 0xff),
|
||||||
|
(byte) ((bitRate >> 16) & 0xff),
|
||||||
|
(byte) ((bitRate >> 24) & 0xff),
|
||||||
|
|
||||||
|
(byte) stopBits,
|
||||||
|
(byte) parity,
|
||||||
|
(byte) dataBits};
|
||||||
|
return sendAcmControlMessage(SET_LINE_CODING, 0, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
mConnection.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||||
|
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
||||||
|
readAmt = Math.min(readAmt, mReadEndpoint.getMaxPacketSize());
|
||||||
|
final int transferred = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
|
||||||
|
timeoutMillis);
|
||||||
|
|
||||||
|
if (transferred < 0) {
|
||||||
|
throw new IOException("Timeout reading timeoutMillis=" + timeoutMillis);
|
||||||
|
}
|
||||||
|
System.arraycopy(mReadBuffer, 0, dest, 0, transferred);
|
||||||
|
return transferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int write(byte[] src, int timeoutMillis) throws IOException {
|
||||||
|
int offset = 0;
|
||||||
|
final int chunksize = mWriteEndpoint.getMaxPacketSize();
|
||||||
|
|
||||||
|
while (offset < src.length) {
|
||||||
|
final byte[] writeBuffer;
|
||||||
|
final int writeLength;
|
||||||
|
|
||||||
|
// bulkTransfer does not support offsets; make a copy if necessary.
|
||||||
|
writeLength = Math.min(src.length - offset, chunksize);
|
||||||
|
if (offset == 0) {
|
||||||
|
writeBuffer = src;
|
||||||
|
} else {
|
||||||
|
writeBuffer = Arrays.copyOfRange(src, offset, offset + writeLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int amt = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
|
||||||
|
timeoutMillis);
|
||||||
|
if (amt <= 0) {
|
||||||
|
throw new IOException("Error writing " + writeLength
|
||||||
|
+ " bytes at offset " + offset + " length=" + src.length);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Wrote amt=" + amt + " attempted=" + writeBuffer.length);
|
||||||
|
offset += amt;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setBaudRate(int baudRate) throws IOException {
|
||||||
|
setAcmLineCoding(baudRate, 0, 0, 8);
|
||||||
|
return baudRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UsbDevice getDevice() {
|
||||||
|
return mDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean probe(UsbDevice usbDevice) {
|
||||||
|
return usbDevice.getVendorId() == 0x2341 && usbDevice.getProductId() == 0x001;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -49,6 +49,20 @@ public enum UsbSerialProber {
|
|||||||
}
|
}
|
||||||
return new FtdiSerialDriver(usbDevice, connection);
|
return new FtdiSerialDriver(usbDevice, connection);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
CDC_ACM_SERIAL {
|
||||||
|
@Override
|
||||||
|
public UsbSerialDriver getDevice(UsbManager manager, UsbDevice usbDevice) {
|
||||||
|
if (!CdcAcmSerialDriver.probe(usbDevice)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final UsbDeviceConnection connection = manager.openDevice(usbDevice);
|
||||||
|
if (connection == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new CdcAcmSerialDriver(usbDevice, connection);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user