From 9af618b3e7b4a8f3e6c9593aa47b7776c0359e63 Mon Sep 17 00:00:00 2001 From: ideniden Date: Thu, 22 Jun 2017 09:02:47 +0800 Subject: [PATCH 1/2] support ch340 --- PhysicaloidLibrary/build.gradle | 4 +- .../src/com/physicaloid/lib/Physicaloid.java | 120 +++ .../com/physicaloid/lib/SerialReceiver.java | 177 ++++ .../src/com/physicaloid/lib/UsbVidList.java | 1 + .../lib/framework/AutoCommunicator.java | 3 + .../lib/usb/driver/uart/UartCH340.java | 303 +++++++ .../lib/usb/driver/uart/UartConfig.java | 5 + .../driver/uart/ext/CH340AndroidDriver.java | 787 ++++++++++++++++++ .../driver/uart/ext/CH341AndroidDriver.java | 786 +++++++++++++++++ SampleProjects/PhysicaloidTest/build.gradle | 2 +- build.gradle | 9 +- 11 files changed, 2190 insertions(+), 7 deletions(-) create mode 100644 PhysicaloidLibrary/src/com/physicaloid/lib/SerialReceiver.java create mode 100644 PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartCH340.java create mode 100644 PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH340AndroidDriver.java create mode 100644 PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH341AndroidDriver.java diff --git a/PhysicaloidLibrary/build.gradle b/PhysicaloidLibrary/build.gradle index b92e072..19ca83d 100644 --- a/PhysicaloidLibrary/build.gradle +++ b/PhysicaloidLibrary/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'android-library' +apply plugin: 'com.android.library' dependencies { compile fileTree(dir: 'libs', include: '*.jar') @@ -6,7 +6,7 @@ dependencies { android { compileSdkVersion 18 - buildToolsVersion '18.1.0' + buildToolsVersion '19.1.0' defaultConfig { minSdkVersion 12 diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/Physicaloid.java b/PhysicaloidLibrary/src/com/physicaloid/lib/Physicaloid.java index 0ea469f..5969fab 100644 --- a/PhysicaloidLibrary/src/com/physicaloid/lib/Physicaloid.java +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/Physicaloid.java @@ -17,6 +17,7 @@ package com.physicaloid.lib; import android.content.Context; +import android.text.TextUtils; import android.util.Log; import com.physicaloid.BuildConfig; @@ -29,6 +30,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; public class Physicaloid { @@ -176,6 +178,124 @@ public int write(byte[] buf, int size) throws RuntimeException { } } + public int write(String str) throws RuntimeException{ + String sendStr=changeEscapeSequence(str, null); + return write(sendStr.getBytes(),sendStr.length()); + } + + public int write(String str,String linefeedCode) throws RuntimeException{ + String sendStr=changeEscapeSequence(str, linefeedCode); + return write(sendStr.getBytes(),sendStr.length()); + } + + /** + * 加入成贞符号 + * @param in + * @param linefeedCode + * @return + */ + private String changeEscapeSequence(String in,String linefeedCode) { + String out = new String(); + try { + out = unescapeJava(in); + } catch (IOException e) { + return ""; + } + if(!TextUtils.isEmpty(linefeedCode))out = out + linefeedCode; + return out; + } + + /** + * 转码 + * @param str + * @return + * @throws IOException + */ + private String unescapeJava(String str) throws IOException { + if (str == null) { + return ""; + } + int sz = str.length(); + StringBuffer unicode = new StringBuffer(4); + + StringBuilder strout = new StringBuilder(); + boolean hadSlash = false; + boolean inUnicode = false; + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); + if (inUnicode) { + // if in unicode, then we're reading unicode + // values in somehow + unicode.append(ch); + if (unicode.length() == 4) { + // unicode now contains the four hex digits + // which represents our unicode character + try { + int value = Integer.parseInt(unicode.toString(), 16); + strout.append((char) value); + unicode.setLength(0); + inUnicode = false; + hadSlash = false; + } catch (NumberFormatException nfe) { + // throw new NestableRuntimeException("Unable to parse unicode value: " + unicode, nfe); + throw new IOException("Unable to parse unicode value: " + unicode, nfe); + } + } + continue; + } + if (hadSlash) { + // handle an escaped value + hadSlash = false; + switch (ch) { + case '\\': + strout.append('\\'); + break; + case '\'': + strout.append('\''); + break; + case '\"': + strout.append('"'); + break; + case 'r': + strout.append('\r'); + break; + case 'f': + strout.append('\f'); + break; + case 't': + strout.append('\t'); + break; + case 'n': + strout.append('\n'); + break; + case 'b': + strout.append('\b'); + break; + case 'u': + { + // uh-oh, we're in unicode country.... + inUnicode = true; + break; + } + default : + strout.append(ch); + break; + } + continue; + } else if (ch == '\\') { + hadSlash = true; + continue; + } + strout.append(ch); + } + if (hadSlash) { + // then we're in the weird case of a \ at the end of the + // string, let's output it anyway. + strout.append('\\'); + } + return new String(strout.toString()); + } + /** * Uploads a binary file to a device on background process. No need to open(). * @param board board profile e.g. Boards.ARDUINO_UNO diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/SerialReceiver.java b/PhysicaloidLibrary/src/com/physicaloid/lib/SerialReceiver.java new file mode 100644 index 0000000..c6158fa --- /dev/null +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/SerialReceiver.java @@ -0,0 +1,177 @@ +package com.physicaloid.lib; + +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +/** + * Created by ideni_000 on 2016/1/10. + */ +public class SerialReceiver { + + Physicaloid mSerial; + SerialReceiverListener mSerialReceiverListener; + public SerialReceiver(Physicaloid mSerial, SerialReceiverListener mSerialReceiverListener) { + this.mSerial = mSerial; + this.mSerialReceiverListener = mSerialReceiverListener; + } + + // occurs USB packet loss if TEXT_MAX_SIZE is over 6000 + private static final int TEXT_MAX_SIZE = 8192; + // Linefeed + private final static String BR = System.getProperty("line.separator"); + // Linefeed Code Settings + private static final int LINEFEED_CODE_CR = 0; + private static final int LINEFEED_CODE_CRLF = 1; + private static final int LINEFEED_CODE_LF = 2; + // Defines of Display Settings + private static final int DISP_CHAR = 0; + private static final int DISP_DEC = 1; + private static final int DISP_HEX = 2; + + //配置 + private int mReadLinefeedCode = LINEFEED_CODE_LF; + private int mDisplayType = DISP_CHAR; + + Handler mHandler=new Handler(){ + @Override + public void handleMessage(Message msg) { +// String line=mText.toString(); + String line = (String) msg.obj; + if(!TextUtils.isEmpty(line)&&line.contains("\n")){ + String[] lines=line.split("\n"); + for (int i=0;i 0) { + switch (mDisplayType) { + case DISP_CHAR: + setSerialDataToTextView(mDisplayType, rbuf, len, "", ""); + break; + case DISP_DEC: + setSerialDataToTextView(mDisplayType, rbuf, len, "013", "010"); + break; + case DISP_HEX: + setSerialDataToTextView(mDisplayType, rbuf, len, "0d", "0a"); + break; + } + mHandler.sendMessage(mHandler.obtainMessage(0,mText.toString())); + mText.setLength(0); + } + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (mStop) { + mRunningMainLoop = false; + return; + } + } + } + }; + + void setSerialDataToTextView(int disp, byte[] rbuf, int len, String sCr, String sLf) { + int tmpbuf; + for (int i = 0; i < len; ++i) { + // "\r":CR(0x0D) "\n":LF(0x0A) + if ((mReadLinefeedCode == LINEFEED_CODE_CR) && (rbuf[i] == 0x0D)) { + mText.append(sCr); + mText.append(BR); + } else if ((mReadLinefeedCode == LINEFEED_CODE_LF) && (rbuf[i] == 0x0A)) { + mText.append(sLf); + mText.append(BR); + } else if ((mReadLinefeedCode == LINEFEED_CODE_CRLF) && (rbuf[i] == 0x0D) + && (rbuf[i + 1] == 0x0A)) { + mText.append(sCr); + if (disp != DISP_CHAR) { + mText.append(" "); + } + mText.append(sLf); + mText.append(BR); + ++i; + } else if ((mReadLinefeedCode == LINEFEED_CODE_CRLF) && (rbuf[i] == 0x0D)) { + // case of rbuf[last] == 0x0D and rbuf[0] == 0x0A + mText.append(sCr); + lastDataIs0x0D = true; + } else if (lastDataIs0x0D && (rbuf[0] == 0x0A)) { + if (disp != DISP_CHAR) { + mText.append(" "); + } + mText.append(sLf); + mText.append(BR); + lastDataIs0x0D = false; + } else if (lastDataIs0x0D && (i != 0)) { + // only disable flag + lastDataIs0x0D = false; + --i; + } else { + switch (disp) { + case DISP_CHAR: + mText.append((char) rbuf[i]); + break; + case DISP_DEC: + tmpbuf = rbuf[i]; + if (tmpbuf < 0) { + tmpbuf += 256; + } + mText.append(String.format("%1$03d", tmpbuf)); + mText.append(" "); + break; + case DISP_HEX: + mText.append(IntToHex2((int) rbuf[i])); + mText.append(" "); + break; + default: + break; + } + } + } + } + + private String IntToHex2(int Value) { + char HEX2[] = { + Character.forDigit((Value >> 4) & 0x0F, 16), + Character.forDigit(Value & 0x0F, 16) + }; + String Hex2Str = new String(HEX2); + return Hex2Str; + } + + public void start(){ + mStop=false; + mRunningMainLoop = true; + new Thread(mLoop).start(); + } + + public void stop(){ + mStop=true; + } + + public boolean isRunning(){ + return mRunningMainLoop; + } + + public interface SerialReceiverListener{ + void onReceive(String line); + } + +} diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/UsbVidList.java b/PhysicaloidLibrary/src/com/physicaloid/lib/UsbVidList.java index 951c02d..153310b 100644 --- a/PhysicaloidLibrary/src/com/physicaloid/lib/UsbVidList.java +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/UsbVidList.java @@ -18,6 +18,7 @@ public enum UsbVidList { ARDUINO (0x2341), + DCCDUINO (0x1A86), FTDI (0x0403), MBED_LPC1768 (0x0d28), MBED_LPC11U24 (0x0d28), diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/framework/AutoCommunicator.java b/PhysicaloidLibrary/src/com/physicaloid/lib/framework/AutoCommunicator.java index 8ebf370..49d7f08 100644 --- a/PhysicaloidLibrary/src/com/physicaloid/lib/framework/AutoCommunicator.java +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/framework/AutoCommunicator.java @@ -21,6 +21,7 @@ import com.physicaloid.lib.UsbVidList; import com.physicaloid.lib.usb.UsbAccessor; +import com.physicaloid.lib.usb.driver.uart.UartCH340; import com.physicaloid.lib.usb.driver.uart.UartCdcAcm; import com.physicaloid.lib.usb.driver.uart.UartCp210x; import com.physicaloid.lib.usb.driver.uart.UartFtdi; @@ -44,6 +45,8 @@ public SerialCommunicator getSerialCommunicator(Context context) { return new UartFtdi(context); } else if(vid == UsbVidList.CP210X.getVid()) { return new UartCp210x(context); + }else if(vid == UsbVidList.DCCDUINO.getVid()){ + return new UartCH340(context); } } } diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartCH340.java b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartCH340.java new file mode 100644 index 0000000..6f4123f --- /dev/null +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartCH340.java @@ -0,0 +1,303 @@ +package com.physicaloid.lib.usb.driver.uart; + +import android.content.Context; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.util.Log; + +import com.physicaloid.BuildConfig; +import com.physicaloid.lib.framework.SerialCommunicator; +import com.physicaloid.lib.usb.driver.uart.ext.CH340AndroidDriver; +import com.physicaloid.misc.RingBuffer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author LuoJ + * @date 2016-1-3 + * @package com.physicaloid.lib.usb.driver.uart -- UartCH340.java + * @Description + */ +public class UartCH340 extends SerialCommunicator { + private static final String TAG = UartCH340.class.getSimpleName(); + private static final boolean DEBUG_SHOW = false && BuildConfig.DEBUG; +// private UsbCdcConnection mUsbConnetionManager; + + private UartConfig mUartConfig; + private static final int RING_BUFFER_SIZE = 1024; + public static final int USB_READ_BUFFER_SIZE = 512; +// byte[] readBuffer=new byte[USB_READ_BUFFER_SIZE]; + private static final int USB_WRITE_BUFFER_SIZE = 512; + private RingBuffer mBuffer; + + private UsbDeviceConnection mConnection; + private int mInterfaceNum; + private boolean isOpened; + + //---- + CH340AndroidDriver mCH340AndroidDriver; + + + public UartCH340(Context context) { + super(context); +// mUsbConnetionManager = new UsbCdcConnection(context); + mUartConfig = new UartConfig(); + mBuffer = new RingBuffer(RING_BUFFER_SIZE); + isOpened = false; + //---- + mCH340AndroidDriver=new CH340AndroidDriver(context); + } + + @Override + public boolean open() { +// for(UsbVidList id : UsbVidList.values()) { +// if(open(new UsbVidPid(id.getVid(), 0))){ +// return true; +// } +// } +// return false; + UsbDevice device = mCH340AndroidDriver.EnumerateDevice(); + if(null!=device){ + boolean open=mCH340AndroidDriver.OpenDevice(device); + if(open&&mCH340AndroidDriver.isConnected()){ + boolean uartInit = mCH340AndroidDriver.UartInit(); + if(uartInit){ + mCH340AndroidDriver.SetConfig(mUartConfig.baudrate, mUartConfig.dataBits, mUartConfig.stopBits, mUartConfig.parity, 0); + isOpened=true; + return true; + } + } + } + return false; + } + + @Override + public boolean close() { + isOpened = false; + return mCH340AndroidDriver.CloseDevice(); + } + + @Override + public int read(byte[] buf, int size) { + return mCH340AndroidDriver.ReadData(buf, size); + } + + @Override + public int write(byte[] buf, int size) { + try { + return mCH340AndroidDriver.WriteData(buf, size); + } catch (IOException e) { + e.printStackTrace(); + } + return 0; + } + + /** + * Sets Uart configurations + * @param config configurations + * @return true : successful, false : fail + */ + public boolean setUartConfig(UartConfig config) { + boolean res = true; + boolean ret = true; + if(mUartConfig.baudrate != config.baudrate) { + res = setBaudrate(config.baudrate); + ret = ret && res; + } + + if(mUartConfig.dataBits != config.dataBits) { + res = setDataBits(config.dataBits); + ret = ret && res; + } + + if(mUartConfig.parity != config.parity) { + res = setParity(config.parity); + ret = ret && res; + } + + if(mUartConfig.stopBits != config.stopBits) { + res = setStopBits(config.stopBits); + ret = ret && res; + } + + if(mUartConfig.dtrOn != config.dtrOn || + mUartConfig.rtsOn != config.rtsOn) { + res = setDtrRts(config.dtrOn, config.rtsOn); + ret = ret && res; + } + + return ret; + } + + @Override + public boolean isOpened() { + return isOpened; + } + + /** + * Sets baudrate + * @param baudrate baudrate e.g. 9600 + * @return true : successful, false : fail + */ + public boolean setBaudrate(int baudrate) { + byte[] baudByte = new byte[4]; + + baudByte[0] = (byte) (baudrate & 0x000000FF); + baudByte[1] = (byte) ((baudrate & 0x0000FF00) >> 8); + baudByte[2] = (byte) ((baudrate & 0x00FF0000) >> 16); + baudByte[3] = (byte) ((baudrate & 0xFF000000) >> 24); + int ret = mConnection.controlTransfer(0x21, 0x20, 0, mInterfaceNum, new byte[] { + baudByte[0], baudByte[1], baudByte[2], baudByte[3], 0x00, 0x00, + 0x08}, 7, 100); + if(ret < 0) { + if(DEBUG_SHOW) { Log.d(TAG, "Fail to setBaudrate"); } + return false; + } + mUartConfig.baudrate = baudrate; + return true; + } + + /** + * Sets Data bits + * @param dataBits data bits e.g. UartConfig.DATA_BITS8 + * @return true : successful, false : fail + */ + public boolean setDataBits(int dataBits) { + // TODO : implement + if(DEBUG_SHOW) { Log.d(TAG, "Fail to setDataBits"); } + mUartConfig.dataBits = dataBits; + return false; + } + + /** + * Sets Parity bit + * @param parity parity bits e.g. UartConfig.PARITY_NONE + * @return true : successful, false : fail + */ + public boolean setParity(int parity) { + // TODO : implement + if(DEBUG_SHOW) { Log.d(TAG, "Fail to setParity"); } + mUartConfig.parity = parity; + return false; + } + + public boolean setFlowControl(int flowControl){ + if(DEBUG_SHOW) { Log.d(TAG, "Fail to setFlowControl"); } + mUartConfig.flowControl = flowControl; + return false; + } + + /** + * Sets Stop bits + * @param stopBits stop bits e.g. UartConfig.STOP_BITS1 + * @return true : successful, false : fail + */ + public boolean setStopBits(int stopBits) { + // TODO : implement + if(DEBUG_SHOW) { Log.d(TAG, "Fail to setStopBits"); } + mUartConfig.stopBits = stopBits; + return false; + } + + @Override + public boolean setDtrRts(boolean dtrOn, boolean rtsOn) { + int ctrlValue = 0x0000; + if(dtrOn) { + ctrlValue |= 0x0001; + } + if(rtsOn) { + ctrlValue |= 0x0002; + } + int ret = mConnection.controlTransfer(0x21, 0x22, ctrlValue, mInterfaceNum, null, 0, 100); + if(ret < 0) { + if(DEBUG_SHOW) { Log.d(TAG, "Fail to setDtrRts"); } + return false; + } + mUartConfig.dtrOn = dtrOn; + mUartConfig.rtsOn = rtsOn; + return true; + } + + @Override + public UartConfig getUartConfig() { + return mUartConfig; + } + + @Override + public int getBaudrate() { + return mUartConfig.baudrate; + } + + @Override + public int getDataBits() { + return mUartConfig.dataBits; + } + + @Override + public int getParity() { + return mUartConfig.parity; + } + + public int getFlowControl(){ + return mUartConfig.flowControl; + } + + @Override + public int getStopBits() { + return mUartConfig.stopBits; + } + + @Override + public boolean getDtr() { + return mUartConfig.dtrOn; + } + + @Override + public boolean getRts() { + return mUartConfig.rtsOn; + } + + @Override + public void clearBuffer() { + mBuffer.clear(); + } + + ////////////////////////////////////////////////////////// + // Listener for reading uart + ////////////////////////////////////////////////////////// + private List uartReadListenerList + = new ArrayList(); + private boolean mStopReadListener = false; + + @Override + public void addReadListener(ReadLisener listener) { + uartReadListenerList.add(listener); + } + + @Override + public void clearReadListener() { + uartReadListenerList.clear(); + } + + @Override + public void startReadListener() { + mStopReadListener = false; + } + + @Override + public void stopReadListener() { + mStopReadListener = true; + } + + private void onRead(int size) { + if(mStopReadListener) return; + for (ReadLisener listener: uartReadListenerList) { + listener.onRead(size); + } + } + ////////////////////////////////////////////////////////// +} + + diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartConfig.java b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartConfig.java index 75f7545..e09d97d 100644 --- a/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartConfig.java +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/UartConfig.java @@ -37,6 +37,7 @@ public class UartConfig { public int dataBits; public int stopBits; public int parity; + public int flowControl; public boolean rtsOn; public boolean dtrOn; @@ -45,6 +46,7 @@ public UartConfig() { this.dataBits = DATA_BITS8; this.stopBits = STOP_BITS1; this.parity = PARITY_NONE; + this.flowControl = FLOW_CONTROL_OFF; this.dtrOn = false; this.rtsOn = false; } @@ -57,4 +59,7 @@ public UartConfig(int baudrate, int dataBits, int stopBits, int parity, boolean this.dtrOn = dtrOn; this.rtsOn = rtsOn; } + + + } diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH340AndroidDriver.java b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH340AndroidDriver.java new file mode 100644 index 0000000..6b6ff95 --- /dev/null +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH340AndroidDriver.java @@ -0,0 +1,787 @@ +package com.physicaloid.lib.usb.driver.uart.ext; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +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.hardware.usb.UsbManager; +import android.util.Log; +import android.widget.Toast; + +public class CH340AndroidDriver { + public static final String TAG = "123456789"; + private UsbManager mUsbmanager; + private PendingIntent mPendingIntent; + private UsbDevice mUsbDevice; + private UsbInterface mInterface; + private UsbEndpoint mCtrlPoint; + private UsbEndpoint mBulkInPoint; + private UsbEndpoint mBulkOutPoint; + private UsbDeviceConnection mDeviceConnection; + private Context mContext; + private String mString; + private boolean BroadcastFlag = false; + public boolean READ_ENABLE = false; + public read_thread readThread; + + private byte [] readBuffer; /*circular buffer*/ + private byte [] usbdata; + private int writeIndex; + private int readIndex; + private int readcount; + private int totalBytes; + private ArrayList DeviceNum = new ArrayList(); + protected final Object ReadQueueLock = new Object(); + protected final Object WriteQueueLock = new Object(); + private int DeviceCount; + private int mBulkPacketSize; + final int maxnumbytes = 65536; + + public int WriteTimeOutMillis; + public int ReadTimeOutMillis; + private int DEFAULT_TIMEOUT = 500; + + public CH340AndroidDriver(Context context) { + super(); + readBuffer = new byte [maxnumbytes]; + usbdata = new byte[1024]; + writeIndex = 0; + readIndex = 0; + + mUsbmanager = (UsbManager) context.getSystemService(Context.USB_SERVICE); + mContext = context; + mString = "USB_PERMISSION"; + WriteTimeOutMillis = 10000; + ReadTimeOutMillis = 10000; + + ArrayAddDevice("1a86:7523"); + //ArrayAddDevice("1a86:5523"); + } + + private void ArrayAddDevice(String str) + { + DeviceNum.add(str); + DeviceCount = DeviceNum.size(); + } + + public boolean SetTimeOut(int WriteTimeOut, int ReadTimeOut) + { + WriteTimeOutMillis = WriteTimeOut; + ReadTimeOutMillis = ReadTimeOut; + return true; + } + + public synchronized boolean OpenUsbDevice(UsbDevice mDevice) + { + + Object localObject; + UsbInterface intf; + if(mDevice == null)return false; + intf = getUsbInterface(mDevice); + if((mDevice != null) && (intf != null)) { + localObject = this.mUsbmanager.openDevice(mDevice); + if(localObject != null) { + if(((UsbDeviceConnection)localObject).claimInterface(intf, true)) { + this.mUsbDevice = mDevice; + this.mDeviceConnection = ((UsbDeviceConnection)localObject); + this.mInterface = intf; + if(!enumerateEndPoint(intf))return false; + Toast.makeText(mContext, "Device Has Attached to Android", Toast.LENGTH_LONG).show(); + if(READ_ENABLE == false){ + READ_ENABLE = true; + readThread = new read_thread(mBulkInPoint, mDeviceConnection); + readThread.start(); + } + return true; + } + } + } + return false; + } + + public synchronized boolean OpenDevice(UsbDevice mDevice) + { + mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mString), 0); + if(mUsbmanager.hasPermission(mDevice)) { + return OpenUsbDevice(mDevice); + } else { + synchronized(mUsbReceiver) { + mUsbmanager.requestPermission(mDevice, mPendingIntent); + } + } + return false; + } + + public synchronized boolean CloseDevice() + { + try{Thread.sleep(10);} + catch(Exception e){} + + if(this.mDeviceConnection != null) + { + if(this.mInterface != null) { + this.mDeviceConnection.releaseInterface(this.mInterface); + this.mInterface = null; + } + + this.mDeviceConnection.close(); + } + + if(this.mUsbDevice != null) { + this.mUsbDevice = null; + } + + if(this.mUsbmanager != null) { + this.mUsbmanager = null; + } + + + if(READ_ENABLE == true) { + READ_ENABLE = false; + } + + /* + * No need unregisterReceiver + */ + if(BroadcastFlag == true) { + this.mContext.unregisterReceiver(mUsbReceiver); + BroadcastFlag = false; + } + return true; +// System.exit(0); + } + + public boolean UsbFeatureSupported() + { + boolean bool = this.mContext.getPackageManager().hasSystemFeature("android.hardware.usb.host"); + return bool; + } + + public int ResumeUsbList() + { + mUsbmanager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + HashMap deviceList = mUsbmanager.getDeviceList(); + Log.i("usbsize","size="+deviceList.size()); + if(deviceList.isEmpty()) { + Toast.makeText(mContext, "No Device Or Device Not Match", Toast.LENGTH_LONG).show(); + return 2; + } + Iterator localIterator = deviceList.values().iterator(); + while(localIterator.hasNext()) { + UsbDevice localUsbDevice = localIterator.next(); + for(int i = 0; i < DeviceCount; ++i) { +// Log.d(TAG, "DeviceCount is " + DeviceCount); + if(String.format("%04x:%04x", new Object[]{Integer.valueOf(localUsbDevice.getVendorId()), + Integer.valueOf(localUsbDevice.getProductId()) }).equals(DeviceNum.get(i))) { + IntentFilter filter = new IntentFilter(mString); + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + mContext.registerReceiver(mUsbReceiver, filter); + BroadcastFlag = true; + if(mUsbmanager.hasPermission(localUsbDevice)) { + OpenUsbDevice(localUsbDevice); + } else { + synchronized(mUsbReceiver) { + mUsbmanager.requestPermission(localUsbDevice, mPendingIntent); + } + } + } else { + Log.d(TAG, "String.format not match"); + } + } + + } + + return 0; + } + + public UsbDevice EnumerateDevice() + { + mUsbmanager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mString), 0); + HashMap deviceList = mUsbmanager.getDeviceList(); + if(deviceList.isEmpty()) { + Toast.makeText(mContext, "No Device Or Device Not Match", Toast.LENGTH_LONG).show(); + return null; + } + Iterator localIterator = deviceList.values().iterator(); + while(localIterator.hasNext()) { + UsbDevice localUsbDevice = localIterator.next(); + for(int i = 0; i < DeviceCount; ++i) { +// Log.d(TAG, "DeviceCount is " + DeviceCount); + if(String.format("%04x:%04x", new Object[]{Integer.valueOf(localUsbDevice.getVendorId()), + Integer.valueOf(localUsbDevice.getProductId()) }).equals(DeviceNum.get(i))) { + IntentFilter filter = new IntentFilter(mString); + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + mContext.registerReceiver(mUsbReceiver, filter); + BroadcastFlag = true; + return localUsbDevice; + + } else { + Log.d(TAG, "String.format not match"); + } + } + } + + return null; + } + + public boolean isConnected() + { + return (this.mUsbDevice != null) && (this.mInterface != null) && (this.mDeviceConnection != null); + } + + protected UsbDevice getUsbDevice() + { + return this.mUsbDevice; + } + + /** + * Performs a control transaction on endpoint zero for this device. + * The direction of the transfer is determined by the request type. + * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is + * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, + * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer + * is a read. + * + * @param requestType request type for this transaction + * @param request request ID for this transaction + * @param value value field for this transaction + * @param index index field for this transaction + * @param buffer buffer for data portion of transaction, + * or null if no data needs to be sent or received + * @param length the length of the data to send or receive + * @param timeout in milliseconds + * @return length of data transferred (or zero) for success, + * or negative value for failure + * + * public int controlTransfer(int requestType, int request, int value, + * int index, byte[] buffer, int length, int timeout) + */ + + public int Uart_Control_Out(int request, int value, int index) + { + int retval = 0; + retval = mDeviceConnection.controlTransfer(UsbType.USB_TYPE_VENDOR | UsbType.USB_RECIP_DEVICE | UsbType.USB_DIR_OUT, + request, value, index, null, 0, DEFAULT_TIMEOUT); + + return retval; + } + + public int Uart_Control_In(int request, int value, int index, byte[] buffer, int length) + { + int retval = 0; + retval = mDeviceConnection.controlTransfer(UsbType.USB_TYPE_VENDOR | UsbType.USB_RECIP_DEVICE | UsbType.USB_DIR_IN, + request, value, index, buffer, length, DEFAULT_TIMEOUT); + return retval; + } + + private int Uart_Set_Handshake(int control) + { + return Uart_Control_Out(UartCmd.VENDOR_MODEM_OUT, ~control, 0); + } + + public int Uart_Tiocmset(int set, int clear) + { + int control = 0; + if((set & UartModem.TIOCM_RTS) == UartModem.TIOCM_RTS) + control |= UartIoBits.UART_BIT_RTS; + if((set & UartModem.TIOCM_DTR) == UartModem.TIOCM_DTR) + control |= UartIoBits.UART_BIT_DTR; + if((clear & UartModem.TIOCM_RTS) == UartModem.TIOCM_RTS) + control &= ~UartIoBits.UART_BIT_RTS; + if((clear & UartModem.TIOCM_DTR) == UartModem.TIOCM_DTR) + control &= ~UartIoBits.UART_BIT_DTR; + + return Uart_Set_Handshake(control); + } + + public boolean UartInit() + { + int ret; + int size = 8; + byte[] buffer = new byte[size]; + Uart_Control_Out(UartCmd.VENDOR_SERIAL_INIT, 0x0000, 0x0000); + ret = Uart_Control_In(UartCmd.VENDOR_VERSION, 0x0000, 0x0000, buffer, 2); + if(ret < 0) + return false; + Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x1312, 0xD982); + Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x0f2c, 0x0004); + ret = Uart_Control_In(UartCmd.VENDOR_READ, 0x2518, 0x0000, buffer, 2); + if(ret < 0) + return false; + Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x2727, 0x0000); + Uart_Control_Out(UartCmd.VENDOR_MODEM_OUT, 0x00ff, 0x0000); + return true; + } + + public boolean SetConfig(int baudRate, int dataBit, int stopBit, int parity, int flowControl) + { + int value = 0; + int index = 0; + char valueHigh = 0, valueLow = 0, indexHigh = 0, indexLow = 0; + switch(parity) { + case 0: /*NONE*/ + valueHigh = 0x00; + break; + case 1: /*ODD*/ + valueHigh |= 0x08; + break; + case 2: /*Even*/ + valueHigh |= 0x18; + break; + case 3: /*Mark*/ + valueHigh |= 0x28; + break; + case 4: /*Space*/ + valueHigh |= 0x38; + break; + default: /*None*/ + valueHigh = 0x00; + break; + } + + if(stopBit == 2) { + valueHigh |= 0x04; + } + + switch(dataBit) { + case 5: + valueHigh |= 0x00; + break; + case 6: + valueHigh |= 0x01; + break; + case 7: + valueHigh |= 0x02; + break; + case 8: + valueHigh |= 0x03; + break; + default: + valueHigh |= 0x03; + break; + } + + valueHigh |= 0xc0; + valueLow = 0x9c; + + value |= valueLow; + value |= (int)(valueHigh << 8); + + switch(baudRate) { + case 50: + indexLow = 0; + indexHigh = 0x16; + break; + case 75: + indexLow = 0; + indexHigh = 0x64; + break; + case 110: + indexLow = 0; + indexHigh = 0x96; + break; + case 135: + indexLow = 0; + indexHigh = 0xa9; + break; + case 150: + indexLow = 0; + indexHigh = 0xb2; + break; + case 300: + indexLow = 0; + indexHigh = 0xd9; + break; + case 600: + indexLow = 1; + indexHigh = 0x64; + break; + case 1200: + indexLow = 1; + indexHigh = 0xb2; + break; + case 1800: + indexLow = 1; + indexHigh = 0xcc; + break; + case 2400: + indexLow = 1; + indexHigh = 0xd9; + break; + case 4800: + indexLow = 2; + indexHigh = 0x64; + break; + case 9600: + indexLow = 2; + indexHigh = 0xb2; + break; + case 19200: + indexLow = 2; + indexHigh = 0xd9; + break; + case 38400: + indexLow = 3; + indexHigh = 0x64; + break; + case 57600: + indexLow = 3; + indexHigh = 0x98; + break; + case 115200: + indexLow = 3; + indexHigh = 0xcc; + break; + case 230400: + indexLow = 3; + indexHigh = 0xe6; + break; + case 460800: + indexLow = 3; + indexHigh = 0xf3; + break; + case 500000: + indexLow = 3; + indexHigh = 0xf4; + break; + case 921600: + indexLow = 7; + indexHigh = 0xf3; + break; + case 1000000: + indexLow = 3; + indexHigh = 0xfa; + break; + case 2000000: + indexLow = 3; + indexHigh = 0xfd; + break; + case 3000000: + indexLow = 3; + indexHigh = 0xfe; + break; + default: // default baudRate "9600" + indexLow = 2; + indexHigh = 0xb2; + break; + } + + index |= 0x88 |indexLow; + index |= (int)(indexHigh << 8); + + Uart_Control_Out(UartCmd.VENDOR_SERIAL_INIT, value, index); + if(flowControl == 1) { + Uart_Tiocmset(UartModem.TIOCM_DTR | UartModem.TIOCM_RTS, 0x00); + } + return true; + } + + public int ReadData(byte[]data, int length) + { + int mLen; + + /*should be at least one byte to read*/ + if((length < 1) || (totalBytes == 0)){ + mLen = 0; + return mLen; + } + + /*check for max limit*/ + if(length > totalBytes) + length = totalBytes; + + /*update the number of bytes available*/ + totalBytes -= length; + + mLen = length; + + /*copy to the user buffer*/ + for(int count = 0; count < length; count++) + { + data[count] = readBuffer[readIndex]; + readIndex++; + /*shouldnt read more than what is there in the buffer, + * so no need to check the overflow + */ + readIndex %= maxnumbytes; + } + return mLen; + } + + public int ReadData(char[]data, int length) + { + int mLen; + + /*should be at least one byte to read*/ + if((length < 1) || (totalBytes == 0)){ + mLen = 0; + return mLen; + } + + /*check for max limit*/ + if(length > totalBytes) + length = totalBytes; + + /*update the number of bytes available*/ + totalBytes -= length; + + mLen = length; + + /*copy to the user buffer*/ + for(int count = 0; count < length; count++) + { + data[count] = (char)readBuffer[readIndex]; + readIndex++; + /*shouldnt read more than what is there in the buffer, + * so no need to check the overflow + */ + readIndex %= maxnumbytes; + } + return mLen; + } + + /** + * Performs a bulk transaction on the given endpoint. + * The direction of the transfer is determined by the direction of the endpoint + * + * @param endpoint the endpoint for this transaction + * @param buffer buffer for data to send or receive, + * @param length the length of the data to send or receive + * @param timeout in milliseconds + * @return length of data transferred (or zero) for success, + * or negative value for failure + * + * public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) + */ + + public int WriteData(byte[] buf, int length) throws IOException + { + int mLen = 0; + mLen = WriteData(buf, length, this.WriteTimeOutMillis); + if(mLen < 0) + { + throw new IOException("Expected Write Actual Bytes"); + } + return mLen; + } + + public int WriteData(byte[] buf, int length, int timeoutMillis) + { + int offset = 0; + int HasWritten = 0; + int odd_len = length; + if(this.mBulkOutPoint == null) + return -1; + while(offset < length) + { + synchronized(this.WriteQueueLock) { + int mLen = Math.min(odd_len, this.mBulkPacketSize); + byte[] arrayOfByte = new byte[mLen]; + if(offset == 0) { + System.arraycopy(buf, 0, arrayOfByte, 0, mLen); + } else { + System.arraycopy(buf, offset, arrayOfByte, 0, mLen); + } + HasWritten = this.mDeviceConnection.bulkTransfer(this.mBulkOutPoint, arrayOfByte, mLen, timeoutMillis); + if(HasWritten < 0) { + return -2; + } else { + offset += HasWritten; + odd_len -= HasWritten; +// Log.d(TAG, "offset " + offset + " odd_len " + odd_len); + } + } + } + return offset; + } + + private boolean enumerateEndPoint(UsbInterface sInterface) + { + if(sInterface == null) + return false; + for(int i = 0; i < sInterface.getEndpointCount(); ++i) { + UsbEndpoint endPoint = sInterface.getEndpoint(i); + if(endPoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK && endPoint.getMaxPacketSize() == 0x20) { + if(endPoint.getDirection() == UsbConstants.USB_DIR_IN) { + mBulkInPoint = endPoint; + } else { + mBulkOutPoint = endPoint; + } + this.mBulkPacketSize = endPoint.getMaxPacketSize(); + } else if(endPoint.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL) { + mCtrlPoint = endPoint; + } + } + return true; + } + + private UsbInterface getUsbInterface(UsbDevice paramUsbDevice) + { + if(this.mDeviceConnection != null) { + if(this.mInterface != null) { + this.mDeviceConnection.releaseInterface(this.mInterface); + this.mInterface = null; + } + this.mDeviceConnection.close(); + this.mUsbDevice = null; + this.mInterface = null; + } + if(paramUsbDevice == null) + return null; + + for (int i = 0; i < paramUsbDevice.getInterfaceCount(); i++) { + UsbInterface intf = paramUsbDevice.getInterface(i); + if (intf.getInterfaceClass() == 0xff + && intf.getInterfaceSubclass() == 0x01 + && intf.getInterfaceProtocol() == 0x02) { + return intf; + } + } + return null; + } + + /***********USB broadcast receiver*******************************************/ + private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() + { + @Override + public void onReceive(Context context, Intent intent) + { +// String action = intent.getAction(); +// if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) +// return; +// +// if(mString.equals(action)) +// { +// synchronized(this) +// { +// UsbDevice localUsbDevice = (UsbDevice)intent.getParcelableExtra("device"); +// if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) +// { +// OpenUsbDevice(localUsbDevice); +// } else { +// Toast.makeText(CH340AndroidDriver.this.mContext, "Deny USB Permission", Toast.LENGTH_SHORT).show(); +// Log.d(TAG, "permission denied"); +// } +// } +// } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { +// Toast.makeText(CH340AndroidDriver.this.mContext, "Disconnect", Toast.LENGTH_SHORT).show(); +// CloseDevice(); +// } else { +// Log.d(TAG, "......"); +// } + } + }; + + /*usb input data handler*/ + private class read_thread extends Thread + { + UsbEndpoint endpoint; + UsbDeviceConnection mConn; + + read_thread(UsbEndpoint point, UsbDeviceConnection con){ + endpoint = point; + mConn = con; + this.setPriority(Thread.MAX_PRIORITY); + } + + public void run() + { + while(READ_ENABLE == true) + { + while(totalBytes > (maxnumbytes - 63)) + { + try + { + Thread.sleep(5); + } + catch (InterruptedException e) {e.printStackTrace();} + } + + synchronized(ReadQueueLock) + { + if(endpoint != null) + { + readcount = mConn.bulkTransfer(endpoint, usbdata, 64, ReadTimeOutMillis); + if(readcount > 0) + { + for(int count = 0; count< readcount; count++) + { + readBuffer[writeIndex] = usbdata[count]; + writeIndex++; + writeIndex %= maxnumbytes; + } + + if(writeIndex >= readIndex) + totalBytes = writeIndex-readIndex; + else + totalBytes = (maxnumbytes-readIndex)+writeIndex; + + } + } + } + } + } + } + + public final class UartModem { + public static final int TIOCM_LE = 0x001; + public static final int TIOCM_DTR = 0x002; + public static final int TIOCM_RTS = 0x004; + public static final int TIOCM_ST = 0x008; + public static final int TIOCM_SR = 0x010; + public static final int TIOCM_CTS = 0x020; + public static final int TIOCM_CAR = 0x040; + public static final int TIOCM_RNG = 0x080; + public static final int TIOCM_DSR = 0x100; + public static final int TIOCM_CD = TIOCM_CAR; + public static final int TIOCM_RI = TIOCM_RNG; + public static final int TIOCM_OUT1 = 0x2000; + public static final int TIOCM_OUT2 = 0x4000; + public static final int TIOCM_LOOP = 0x8000; + } + + public final class UsbType { + public static final int USB_TYPE_VENDOR = (0x02 << 5); + public static final int USB_RECIP_DEVICE = 0x00; + public static final int USB_DIR_OUT = 0x00; /*to device*/ + public static final int USB_DIR_IN = 0x80; /*to host*/ + } + + public final class UartCmd { + public static final int VENDOR_WRITE_TYPE = 0x40; + public static final int VENDOR_READ_TYPE = 0xC0; + public static final int VENDOR_READ = 0x95; + public static final int VENDOR_WRITE = 0x9A; + public static final int VENDOR_SERIAL_INIT = 0xA1; + public static final int VENDOR_MODEM_OUT = 0xA4; + public static final int VENDOR_VERSION = 0x5F; + } + + public final class UartState { + public static final int UART_STATE = 0x00; + public static final int UART_OVERRUN_ERROR = 0x01; + public static final int UART_PARITY_ERROR = 0x02; + public static final int UART_FRAME_ERROR = 0x06; + public static final int UART_RECV_ERROR = 0x02; + public static final int UART_STATE_TRANSIENT_MASK = 0x07; + } + + public final class UartIoBits { + public static final int UART_BIT_RTS = (1 << 6); + public static final int UART_BIT_DTR = (1 << 5); + } +} + + diff --git a/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH341AndroidDriver.java b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH341AndroidDriver.java new file mode 100644 index 0000000..ba24fbb --- /dev/null +++ b/PhysicaloidLibrary/src/com/physicaloid/lib/usb/driver/uart/ext/CH341AndroidDriver.java @@ -0,0 +1,786 @@ +package com.physicaloid.lib.usb.driver.uart.ext; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +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.hardware.usb.UsbManager; +import android.util.Log; +import android.widget.Toast; + +public class CH341AndroidDriver { + public static final String TAG = "123456789"; + private UsbManager mUsbmanager; + private PendingIntent mPendingIntent; + private UsbDevice mUsbDevice; + private UsbInterface mInterface; + private UsbEndpoint mCtrlPoint; + private UsbEndpoint mBulkInPoint; + private UsbEndpoint mBulkOutPoint; + private UsbDeviceConnection mDeviceConnection; + private Context mContext; + private String mString; + private boolean BroadcastFlag = false; + public boolean READ_ENABLE = false; + public read_thread readThread; + + private byte [] readBuffer; /*circular buffer*/ + private byte [] usbdata; + private int writeIndex; + private int readIndex; + private int readcount; + private int totalBytes; + private ArrayList DeviceNum = new ArrayList(); + protected final Object ReadQueueLock = new Object(); + protected final Object WriteQueueLock = new Object(); + private int DeviceCount; + private int mBulkPacketSize; + final int maxnumbytes = 65536; + + public int WriteTimeOutMillis; + public int ReadTimeOutMillis; + private int DEFAULT_TIMEOUT = 500; + + public CH341AndroidDriver(UsbManager manager,Context context, String AppName) { + super(); + readBuffer = new byte [maxnumbytes]; + usbdata = new byte[1024]; + writeIndex = 0; + readIndex = 0; + + mUsbmanager = manager; + mContext = context; + mString = AppName; + WriteTimeOutMillis = 10000; + ReadTimeOutMillis = 10000; + ArrayAddDevice("1a86:5523"); + } + + private void ArrayAddDevice(String str) + { + DeviceNum.add(str); + DeviceCount = DeviceNum.size(); + } + + public boolean SetTimeOut(int WriteTimeOut, int ReadTimeOut) + { + WriteTimeOutMillis = WriteTimeOut; + ReadTimeOutMillis = ReadTimeOut; + return true; + } + + public synchronized void OpenUsbDevice(UsbDevice mDevice) + { + + Object localObject; + UsbInterface intf; + if(mDevice == null) + return; + intf = getUsbInterface(mDevice); + if((mDevice != null) && (intf != null)) { + localObject = this.mUsbmanager.openDevice(mDevice); + if(localObject != null) { + if(((UsbDeviceConnection)localObject).claimInterface(intf, true)) { + this.mUsbDevice = mDevice; + this.mDeviceConnection = ((UsbDeviceConnection)localObject); + this.mInterface = intf; + if(!enumerateEndPoint(intf)) + return; + Toast.makeText(mContext, "Device Has Attached to Android", Toast.LENGTH_LONG).show(); + if(READ_ENABLE == false){ + READ_ENABLE = true; + readThread = new read_thread(mBulkInPoint, mDeviceConnection); + readThread.start(); + } + return; + } + } + } + + } + + public synchronized void OpenDevice(UsbDevice mDevice) + { + mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mString), 0); + if(mUsbmanager.hasPermission(mDevice)) { + OpenUsbDevice(mDevice); + } else { + synchronized(mUsbReceiver) { + mUsbmanager.requestPermission(mDevice, mPendingIntent); + } + } + } + + public synchronized void CloseDevice() + { + try{Thread.sleep(10);} + catch(Exception e){} + + if(this.mDeviceConnection != null) + { + if(this.mInterface != null) { + this.mDeviceConnection.releaseInterface(this.mInterface); + this.mInterface = null; + } + + this.mDeviceConnection.close(); + } + + if(this.mUsbDevice != null) { + this.mUsbDevice = null; + } + + if(this.mUsbmanager != null) { + this.mUsbmanager = null; + } + + + if(READ_ENABLE == true) { + READ_ENABLE = false; + } + + /* + * No need unregisterReceiver + */ + if(BroadcastFlag == true) { + this.mContext.unregisterReceiver(mUsbReceiver); + BroadcastFlag = false; + } + +// System.exit(0); + } + + public boolean UsbFeatureSupported() + { + boolean bool = this.mContext.getPackageManager().hasSystemFeature("android.hardware.usb.host"); + return bool; + } + + public int ResumeUsbList() + { + mUsbmanager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + HashMap deviceList = mUsbmanager.getDeviceList(); + Log.i("usbsize","size="+deviceList .size()); + if(deviceList.isEmpty()) { + Toast.makeText(mContext, "No Device Or Device Not Match", Toast.LENGTH_LONG).show(); + return 2; + } + Iterator localIterator = deviceList.values().iterator(); + while(localIterator.hasNext()) { + UsbDevice localUsbDevice = localIterator.next(); + for(int i = 0; i < DeviceCount; ++i) { +// Log.d(TAG, "DeviceCount is " + DeviceCount); + if(String.format("%04x:%04x", new Object[]{Integer.valueOf(localUsbDevice.getVendorId()), + Integer.valueOf(localUsbDevice.getProductId()) }).equals(DeviceNum.get(i))) { + IntentFilter filter = new IntentFilter(mString); + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + mContext.registerReceiver(mUsbReceiver, filter); + BroadcastFlag = true; + if(mUsbmanager.hasPermission(localUsbDevice)) { + OpenUsbDevice(localUsbDevice); + } else { + synchronized(mUsbReceiver) { + mUsbmanager.requestPermission(localUsbDevice, mPendingIntent); + } + } + } else { + Log.d(TAG, "String.format not match"); + } + } + + } + + return 0; + } + + public UsbDevice EnumerateDevice() + { + mUsbmanager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mString), 0); + HashMap deviceList = mUsbmanager.getDeviceList(); + if(deviceList.isEmpty()) { + Toast.makeText(mContext, "No Device Or Device Not Match", Toast.LENGTH_LONG).show(); + return null; + } + Iterator localIterator = deviceList.values().iterator(); + while(localIterator.hasNext()) { + UsbDevice localUsbDevice = localIterator.next(); + for(int i = 0; i < DeviceCount; ++i) { +// Log.d(TAG, "DeviceCount is " + DeviceCount); + if(String.format("%04x:%04x", new Object[]{Integer.valueOf(localUsbDevice.getVendorId()), + Integer.valueOf(localUsbDevice.getProductId()) }).equals(DeviceNum.get(i))) { + IntentFilter filter = new IntentFilter(mString); + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + mContext.registerReceiver(mUsbReceiver, filter); + BroadcastFlag = true; + return localUsbDevice; + + } else { + Log.d(TAG, "String.format not match"); + } + } + } + + return null; + } + + public boolean isConnected() + { + return (this.mUsbDevice != null) && (this.mInterface != null) && (this.mDeviceConnection != null); + } + + protected UsbDevice getUsbDevice() + { + return this.mUsbDevice; + } + + /** + * Performs a control transaction on endpoint zero for this device. + * The direction of the transfer is determined by the request type. + * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is + * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, + * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer + * is a read. + * + * @param requestType request type for this transaction + * @param request request ID for this transaction + * @param value value field for this transaction + * @param index index field for this transaction + * @param buffer buffer for data portion of transaction, + * or null if no data needs to be sent or received + * @param length the length of the data to send or receive + * @param timeout in milliseconds + * @return length of data transferred (or zero) for success, + * or negative value for failure + * + * public int controlTransfer(int requestType, int request, int value, + * int index, byte[] buffer, int length, int timeout) + */ + + public int Uart_Control_Out(int request, int value, int index) + { + int retval = 0; + retval = mDeviceConnection.controlTransfer(UsbType.USB_TYPE_VENDOR | UsbType.USB_RECIP_DEVICE | UsbType.USB_DIR_OUT, + request, value, index, null, 0, DEFAULT_TIMEOUT); + + return retval; + } + + public int Uart_Control_In(int request, int value, int index, byte[] buffer, int length) + { + int retval = 0; + retval = mDeviceConnection.controlTransfer(UsbType.USB_TYPE_VENDOR | UsbType.USB_RECIP_DEVICE | UsbType.USB_DIR_IN, + request, value, index, buffer, length, DEFAULT_TIMEOUT); + return retval; + } + + private int Uart_Set_Handshake(int control) + { + return Uart_Control_Out(UartCmd.VENDOR_MODEM_OUT, ~control, 0); + } + + public int Uart_Tiocmset(int set, int clear) + { + int control = 0; + if((set & UartModem.TIOCM_RTS) == UartModem.TIOCM_RTS) + control |= UartIoBits.UART_BIT_RTS; + if((set & UartModem.TIOCM_DTR) == UartModem.TIOCM_DTR) + control |= UartIoBits.UART_BIT_DTR; + if((clear & UartModem.TIOCM_RTS) == UartModem.TIOCM_RTS) + control &= ~UartIoBits.UART_BIT_RTS; + if((clear & UartModem.TIOCM_DTR) == UartModem.TIOCM_DTR) + control &= ~UartIoBits.UART_BIT_DTR; + + return Uart_Set_Handshake(control); + } + + public boolean UartInit() + { + int ret; + int size = 8; + byte[] buffer = new byte[size]; + Uart_Control_Out(UartCmd.VENDOR_SERIAL_INIT, 0x0000, 0x0000); + ret = Uart_Control_In(UartCmd.VENDOR_VERSION, 0x0000, 0x0000, buffer, 2); + if(ret < 0) + return false; + Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x1312, 0xD982); + Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x0f2c, 0x0004); + ret = Uart_Control_In(UartCmd.VENDOR_READ, 0x2518, 0x0000, buffer, 2); + if(ret < 0) + return false; + Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x2727, 0x0000); + Uart_Control_Out(UartCmd.VENDOR_MODEM_OUT, 0x00ff, 0x0000); + return true; + } + + public boolean SetConfig(int baudRate, byte dataBit, byte stopBit, byte parity, byte flowControl) + { + int value = 0; + int index = 0; + char valueHigh = 0, valueLow = 0, indexHigh = 0, indexLow = 0; + switch(parity) { + case 0: /*NONE*/ + valueHigh = 0x00; + break; + case 1: /*ODD*/ + valueHigh |= 0x08; + break; + case 2: /*Even*/ + valueHigh |= 0x18; + break; + case 3: /*Mark*/ + valueHigh |= 0x28; + break; + case 4: /*Space*/ + valueHigh |= 0x38; + break; + default: /*None*/ + valueHigh = 0x00; + break; + } + + if(stopBit == 2) { + valueHigh |= 0x04; + } + + switch(dataBit) { + case 5: + valueHigh |= 0x00; + break; + case 6: + valueHigh |= 0x01; + break; + case 7: + valueHigh |= 0x02; + break; + case 8: + valueHigh |= 0x03; + break; + default: + valueHigh |= 0x03; + break; + } + + valueHigh |= 0xc0; + valueLow = 0x9c; + + value |= valueLow; + value |= (int)(valueHigh << 8); + + switch(baudRate) { + case 50: + indexLow = 0; + indexHigh = 0x16; + break; + case 75: + indexLow = 0; + indexHigh = 0x64; + break; + case 110: + indexLow = 0; + indexHigh = 0x96; + break; + case 135: + indexLow = 0; + indexHigh = 0xa9; + break; + case 150: + indexLow = 0; + indexHigh = 0xb2; + break; + case 300: + indexLow = 0; + indexHigh = 0xd9; + break; + case 600: + indexLow = 1; + indexHigh = 0x64; + break; + case 1200: + indexLow = 1; + indexHigh = 0xb2; + break; + case 1800: + indexLow = 1; + indexHigh = 0xcc; + break; + case 2400: + indexLow = 1; + indexHigh = 0xd9; + break; + case 4800: + indexLow = 2; + indexHigh = 0x64; + break; + case 9600: + indexLow = 2; + indexHigh = 0xb2; + break; + case 19200: + indexLow = 2; + indexHigh = 0xd9; + break; + case 38400: + indexLow = 3; + indexHigh = 0x64; + break; + case 57600: + indexLow = 3; + indexHigh = 0x98; + break; + case 115200: + indexLow = 3; + indexHigh = 0xcc; + break; + case 230400: + indexLow = 3; + indexHigh = 0xe6; + break; + case 460800: + indexLow = 3; + indexHigh = 0xf3; + break; + case 500000: + indexLow = 3; + indexHigh = 0xf4; + break; + case 921600: + indexLow = 7; + indexHigh = 0xf3; + break; + case 1000000: + indexLow = 3; + indexHigh = 0xfa; + break; + case 2000000: + indexLow = 3; + indexHigh = 0xfd; + break; + case 3000000: + indexLow = 3; + indexHigh = 0xfe; + break; + default: // default baudRate "9600" + indexLow = 2; + indexHigh = 0xb2; + break; + } + + index |= 0x88 |indexLow; + index |= (int)(indexHigh << 8); + + Uart_Control_Out(UartCmd.VENDOR_SERIAL_INIT, value, index); + if(flowControl == 1) { + Uart_Tiocmset(UartModem.TIOCM_DTR | UartModem.TIOCM_RTS, 0x00); + } + return true; + } + + public int ReadData(byte[]data, int length) + { + int mLen; + + /*should be at least one byte to read*/ + if((length < 1) || (totalBytes == 0)){ + mLen = 0; + return mLen; + } + + /*check for max limit*/ + if(length > totalBytes) + length = totalBytes; + + /*update the number of bytes available*/ + totalBytes -= length; + + mLen = length; + + /*copy to the user buffer*/ + for(int count = 0; count < length; count++) + { + data[count] = readBuffer[readIndex]; + readIndex++; + /*shouldnt read more than what is there in the buffer, + * so no need to check the overflow + */ + readIndex %= maxnumbytes; + } + return mLen; + } + + public int ReadData(char[]data, int length) + { + int mLen; + + /*should be at least one byte to read*/ + if((length < 1) || (totalBytes == 0)){ + mLen = 0; + return mLen; + } + + /*check for max limit*/ + if(length > totalBytes) + length = totalBytes; + + /*update the number of bytes available*/ + totalBytes -= length; + + mLen = length; + + /*copy to the user buffer*/ + for(int count = 0; count < length; count++) + { + data[count] = (char)readBuffer[readIndex]; + readIndex++; + /*shouldnt read more than what is there in the buffer, + * so no need to check the overflow + */ + readIndex %= maxnumbytes; + } + return mLen; + } + + /** + * Performs a bulk transaction on the given endpoint. + * The direction of the transfer is determined by the direction of the endpoint + * + * @param endpoint the endpoint for this transaction + * @param buffer buffer for data to send or receive, + * @param length the length of the data to send or receive + * @param timeout in milliseconds + * @return length of data transferred (or zero) for success, + * or negative value for failure + * + * public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) + */ + + public int WriteData(byte[] buf, int length) throws IOException + { + int mLen = 0; + mLen = WriteData(buf, length, this.WriteTimeOutMillis); + if(mLen < 0) + { + throw new IOException("Expected Write Actual Bytes"); + } + return mLen; + } + + public int WriteData(byte[] buf, int length, int timeoutMillis) + { + int offset = 0; + int HasWritten = 0; + int odd_len = length; + if(this.mBulkOutPoint == null) + return -1; + while(offset < length) + { + synchronized(this.WriteQueueLock) { + int mLen = Math.min(odd_len, this.mBulkPacketSize); + byte[] arrayOfByte = new byte[mLen]; + if(offset == 0) { + System.arraycopy(buf, 0, arrayOfByte, 0, mLen); + } else { + System.arraycopy(buf, offset, arrayOfByte, 0, mLen); + } + HasWritten = this.mDeviceConnection.bulkTransfer(this.mBulkOutPoint, arrayOfByte, mLen, timeoutMillis); + if(HasWritten < 0) { + return -2; + } else { + offset += HasWritten; + odd_len -= HasWritten; +// Log.d(TAG, "offset " + offset + " odd_len " + odd_len); + } + } + } + return offset; + } + + private boolean enumerateEndPoint(UsbInterface sInterface) + { + if(sInterface == null) + return false; + for(int i = 0; i < sInterface.getEndpointCount(); ++i) { + UsbEndpoint endPoint = sInterface.getEndpoint(i); + if(endPoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK && endPoint.getMaxPacketSize() == 0x20) { + if(endPoint.getDirection() == UsbConstants.USB_DIR_IN) { + mBulkInPoint = endPoint; + } else { + mBulkOutPoint = endPoint; + } + this.mBulkPacketSize = endPoint.getMaxPacketSize(); + } else if(endPoint.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL) { + mCtrlPoint = endPoint; + } + } + return true; + } + + private UsbInterface getUsbInterface(UsbDevice paramUsbDevice) + { + if(this.mDeviceConnection != null) { + if(this.mInterface != null) { + this.mDeviceConnection.releaseInterface(this.mInterface); + this.mInterface = null; + } + this.mDeviceConnection.close(); + this.mUsbDevice = null; + this.mInterface = null; + } + if(paramUsbDevice == null) + return null; + + for (int i = 0; i < paramUsbDevice.getInterfaceCount(); i++) { + UsbInterface intf = paramUsbDevice.getInterface(i); + if (intf.getInterfaceClass() == 0xff + && intf.getInterfaceSubclass() == 0x01 + && intf.getInterfaceProtocol() == 0x02) { + return intf; + } + } + return null; + } + + /***********USB broadcast receiver*******************************************/ + private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() + { + @Override + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) + return; + + if(mString.equals(action)) + { + synchronized(this) + { + UsbDevice localUsbDevice = (UsbDevice)intent.getParcelableExtra("device"); + if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) + { + OpenUsbDevice(localUsbDevice); + } else { + Toast.makeText(CH341AndroidDriver.this.mContext, "Deny USB Permission", Toast.LENGTH_SHORT).show(); + Log.d(TAG, "permission denied"); + } + } + } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { + Toast.makeText(CH341AndroidDriver.this.mContext, "Disconnect", Toast.LENGTH_SHORT).show(); + CloseDevice(); + } else { + Log.d(TAG, "......"); + } + } + }; + + /*usb input data handler*/ + private class read_thread extends Thread + { + UsbEndpoint endpoint; + UsbDeviceConnection mConn; + + read_thread(UsbEndpoint point, UsbDeviceConnection con){ + endpoint = point; + mConn = con; + this.setPriority(Thread.MAX_PRIORITY); + } + + public void run() + { + while(READ_ENABLE == true) + { + while(totalBytes > (maxnumbytes - 63)) + { + try + { + Thread.sleep(5); + } + catch (InterruptedException e) {e.printStackTrace();} + } + + synchronized(ReadQueueLock) + { + if(endpoint != null) + { + readcount = mConn.bulkTransfer(endpoint, usbdata, 64, ReadTimeOutMillis); + if(readcount > 0) + { + for(int count = 0; count< readcount; count++) + { + readBuffer[writeIndex] = usbdata[count]; + writeIndex++; + writeIndex %= maxnumbytes; + } + + if(writeIndex >= readIndex) + totalBytes = writeIndex-readIndex; + else + totalBytes = (maxnumbytes-readIndex)+writeIndex; + + } + } + } + } + } + } + + public final class UartModem { + public static final int TIOCM_LE = 0x001; + public static final int TIOCM_DTR = 0x002; + public static final int TIOCM_RTS = 0x004; + public static final int TIOCM_ST = 0x008; + public static final int TIOCM_SR = 0x010; + public static final int TIOCM_CTS = 0x020; + public static final int TIOCM_CAR = 0x040; + public static final int TIOCM_RNG = 0x080; + public static final int TIOCM_DSR = 0x100; + public static final int TIOCM_CD = TIOCM_CAR; + public static final int TIOCM_RI = TIOCM_RNG; + public static final int TIOCM_OUT1 = 0x2000; + public static final int TIOCM_OUT2 = 0x4000; + public static final int TIOCM_LOOP = 0x8000; + } + + public final class UsbType { + public static final int USB_TYPE_VENDOR = (0x02 << 5); + public static final int USB_RECIP_DEVICE = 0x00; + public static final int USB_DIR_OUT = 0x00; /*to device*/ + public static final int USB_DIR_IN = 0x80; /*to host*/ + } + + public final class UartCmd { + public static final int VENDOR_WRITE_TYPE = 0x40; + public static final int VENDOR_READ_TYPE = 0xC0; + public static final int VENDOR_READ = 0x95; + public static final int VENDOR_WRITE = 0x9A; + public static final int VENDOR_SERIAL_INIT = 0xA1; + public static final int VENDOR_MODEM_OUT = 0xA4; + public static final int VENDOR_VERSION = 0x5F; + } + + public final class UartState { + public static final int UART_STATE = 0x00; + public static final int UART_OVERRUN_ERROR = 0x01; + public static final int UART_PARITY_ERROR = 0x02; + public static final int UART_FRAME_ERROR = 0x06; + public static final int UART_RECV_ERROR = 0x02; + public static final int UART_STATE_TRANSIENT_MASK = 0x07; + } + + public final class UartIoBits { + public static final int UART_BIT_RTS = (1 << 6); + public static final int UART_BIT_DTR = (1 << 5); + } +} + + diff --git a/SampleProjects/PhysicaloidTest/build.gradle b/SampleProjects/PhysicaloidTest/build.gradle index d44ba31..ca77812 100644 --- a/SampleProjects/PhysicaloidTest/build.gradle +++ b/SampleProjects/PhysicaloidTest/build.gradle @@ -6,7 +6,7 @@ dependencies { android { compileSdkVersion 18 - buildToolsVersion '18.0.1' + buildToolsVersion '19.1.0' defaultConfig { minSdkVersion 12 diff --git a/build.gradle b/build.gradle index 7f338f3..c2eba1a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,11 @@ buildscript { repositories { mavenCentral() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.5.+' + classpath 'com.android.tools.build:gradle:2.2.2' } } @@ -16,7 +17,7 @@ allprojects { mavenCentral() } - tasks.withType(Compile) { - options.encoding = "UTF-8" - } +// tasks.withType(Compile) { +// options.encoding = "UTF-8" +// } } \ No newline at end of file From 8c0ee8a15147e9fd1e348737592f04eeedeff74f Mon Sep 17 00:00:00 2001 From: luoj Date: Thu, 22 Jun 2017 09:09:41 +0800 Subject: [PATCH 2/2] append support ch340 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2975df8..d7c56cb 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Features - upload a firmware to an Arduino - support on Android 3.1 or higher (need USB Host API feature) - **does not require ROOT** -- support USB-Serial protocols : CDC-ACM, FTDI, Silicon Labs CP210x +- support USB-Serial protocols : CDC-ACM, FTDI, Silicon Labs CP210x, CH340 - support uploading firmware protocols : STK500, STK500V2 - open-source(Apache License 2.0)