mirror of
				https://github.com/mik3y/usb-serial-for-android
				synced 2025-10-31 02:17:23 +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