Initial CDC ACM support.

Tested on Arduino Uno.
pull/36/head
mike wakerly 2012-06-26 23:15:48 -07:00
rodzic f801b31997
commit b4b6d147ea
3 zmienionych plików z 175 dodań i 0 usunięć

Wyświetl plik

@ -2,4 +2,6 @@
<resources>
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
<usb-device vendor-id="1027" product-id="24577" />
<!-- 0x2341 / 0x0001: Arduino Uno -->
<usb-device vendor-id="9025" product-id="1" />
</resources>

Wyświetl plik

@ -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;
}
}

Wyświetl plik

@ -49,6 +49,20 @@ public enum UsbSerialProber {
}
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);
}
};
/**