├── settings.gradle ├── .idea ├── .gitignore ├── vcs.xml ├── runConfigurations.xml ├── modules.xml └── misc.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── usbSerialExamples ├── src │ └── main │ │ ├── res │ │ ├── drawable-hdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-ldpi │ │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ │ └── ic_launcher.png │ │ ├── values │ │ │ └── strings.xml │ │ ├── xml │ │ │ └── device_filter.xml │ │ └── layout │ │ │ ├── main.xml │ │ │ └── serial_console.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── hoho │ │ └── android │ │ └── usbserial │ │ └── examples │ │ ├── DeviceListActivity.java │ │ └── SerialConsoleActivity.java └── build.gradle ├── usbSerialForAndroid ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── hoho │ │ │ └── android │ │ │ └── usbserial │ │ │ ├── driver │ │ │ ├── UsbSerialRuntimeException.java │ │ │ ├── UsbSerialDriver.java │ │ │ ├── UsbId.java │ │ │ ├── ProbeTable.java │ │ │ ├── UsbSerialProber.java │ │ │ ├── CommonUsbSerialPort.java │ │ │ ├── UsbSerialPort.java │ │ │ ├── Ch34xSerialDriver.java │ │ │ ├── Cp21xxSerialDriver.java │ │ │ ├── CdcAcmSerialDriver.java │ │ │ ├── FtdiSerialDriver.java │ │ │ └── ProlificSerialDriver.java │ │ │ └── util │ │ │ ├── HexDump.java │ │ │ └── SerialInputOutputManager.java │ └── androidTest │ │ └── AndroidManifest.xml ├── publishToMavenLocal.gradle └── build.gradle ├── .gitignore ├── CHANGELOG.txt ├── test ├── serial_test │ └── serial_test.ino ├── rfc2217_server.diff └── arduino_leonardo_bridge │ └── arduino_leonardo_bridge.ino ├── gradlew.bat ├── gradlew ├── README.md └── LICENSE.txt /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'usbSerialForAndroid', 'usbSerialExamples' 2 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | caches 2 | codeStyles 3 | libraries 4 | workspace.xml 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kai-morich/usb-serial-for-android/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kai-morich/usb-serial-for-android/HEAD/usbSerialExamples/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kai-morich/usb-serial-for-android/HEAD/usbSerialExamples/src/main/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kai-morich/usb-serial-for-android/HEAD/usbSerialExamples/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Oct 06 09:46:24 CEST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | USB Serial Example 5 | Serial Example 6 | Refreshing... 7 | RTS - Request To Send 8 | DTR - Data Terminal Ready 9 | 10 | 11 | -------------------------------------------------------------------------------- /usbSerialExamples/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion '28.0.3' 6 | 7 | defaultConfig { 8 | minSdkVersion 17 9 | targetSdkVersion 28 10 | 11 | testInstrumentationRunner "android.test.InstrumentationTestRunner" 12 | } 13 | 14 | buildTypes { 15 | release { 16 | minifyEnabled true 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation project(':usbSerialForAndroid') 23 | } 24 | -------------------------------------------------------------------------------- /usbSerialForAndroid/publishToMavenLocal.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | 3 | publishing { 4 | publications { 5 | maven(MavenPublication) { 6 | groupId 'com.github.mik3y' 7 | artifactId 'usb-serial-for-android' 8 | version '1.x.0' 9 | afterEvaluate { 10 | artifact androidSourcesJar 11 | artifact bundleReleaseAar 12 | } 13 | } 14 | } 15 | } 16 | 17 | task androidSourcesJar(type: Jar) { 18 | classifier 'sources' 19 | from android.sourceSets.main.java.srcDirs 20 | } 21 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Studio/Gradle 16 | *.iml 17 | .gradle/ 18 | build/ 19 | 20 | # User-specific stuff: 21 | .idea/workspace.xml 22 | .idea/tasks.xml 23 | .idea/dictionaries 24 | 25 | # Sensitive or high-churn files: 26 | .idea/dataSources.ids 27 | .idea/dataSources.xml 28 | .idea/sqlDataSources.xml 29 | .idea/dynamic.xml 30 | .idea/uiDesigner.xml 31 | 32 | # Gradle: 33 | .idea/gradle.xml 34 | .idea/libraries 35 | 36 | # Eclipse/Android/Misc 37 | .metadata/ 38 | local.properties 39 | *.DS_Store 40 | proguard/ 41 | 42 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Current Version (in development) 2 | * Gradle, Android Studio support. 3 | * New driver: CP2102 (thanks Ducky). 4 | * New prober support: LUFA Virtual Serial, Leaflabs Maple, Teensyduino. 5 | * New driver methods: getCD, getCTS, getDSR, getDTR, setDTR, getRI, getRTS, 6 | setRTS. 7 | * API change: setBaudrate() has been removed; use setParameters(). 8 | * API change: open() no longer implicitly sets the baud rate. Clients should 9 | call setParameters() immediately after open(), when necessary. 10 | * Library version is available in `com.hoho.android.usbserial.BuildInfo`. 11 | 12 | v0.1.0 (2012-10-12) 13 | * New driver: CdcAcmSerialDriver. 14 | * Better tuned read and write buffer sizes. 15 | 16 | v0.0.1 (2011-12-28) 17 | * Initial release. 18 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/xml/device_filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /usbSerialForAndroid/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion '28.0.3' 6 | 7 | defaultConfig { 8 | minSdkVersion 17 9 | targetSdkVersion 28 10 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | testImplementation 'junit:junit:4.12' 23 | androidTestImplementation 'com.android.support:support-annotations:28.0.0' 24 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 25 | androidTestImplementation 'commons-net:commons-net:3.6' 26 | androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1' 27 | } 28 | 29 | // to build a .jar file use gradle task 'createFullJarRelease' 30 | 31 | // to deploy into local maven repository use gradle task 'publishToMavenLocal' and enable: 32 | //apply from: 'publishToMavenLocal.gradle' 33 | -------------------------------------------------------------------------------- /test/serial_test/serial_test.ino: -------------------------------------------------------------------------------- 1 | /* Copyright 2012 Google Inc. 2 | * 3 | * This library is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU Lesser General Public 5 | * License as published by the Free Software Foundation; either 6 | * version 2.1 of the License, or (at your option) any later version. 7 | * 8 | * This library is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public 14 | * License along with this library; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 16 | * USA. 17 | * 18 | * Project home page: http://code.google.com/p/usb-serial-for-android/ 19 | */ 20 | 21 | // Sample Arduino sketch for use with usb-serial-for-android. 22 | // Prints an ever-increasing counter, and writes back anything 23 | // it receives. 24 | 25 | static int counter = 0; 26 | void setup() { 27 | Serial.begin(115200); 28 | } 29 | 30 | void loop() { 31 | Serial.print("Tick #"); 32 | Serial.print(counter++, DEC); 33 | Serial.print("\n"); 34 | 35 | if (Serial.peek() != -1) { 36 | Serial.print("Read: "); 37 | do { 38 | Serial.print((char) Serial.read()); 39 | } while (Serial.peek() != -1); 40 | Serial.print("\n"); 41 | } 42 | delay(1000); 43 | } 44 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | */ 19 | 20 | package com.hoho.android.usbserial.driver; 21 | 22 | /** 23 | * Generic unchecked exception for the usbserial package. 24 | * 25 | * @author mike wakerly (opensource@hoho.com) 26 | */ 27 | @SuppressWarnings("serial") 28 | public class UsbSerialRuntimeException extends RuntimeException { 29 | 30 | public UsbSerialRuntimeException() { 31 | super(); 32 | } 33 | 34 | public UsbSerialRuntimeException(String detailMessage, Throwable throwable) { 35 | super(detailMessage, throwable); 36 | } 37 | 38 | public UsbSerialRuntimeException(String detailMessage) { 39 | super(detailMessage); 40 | } 41 | 42 | public UsbSerialRuntimeException(Throwable throwable) { 43 | super(throwable); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDevice; 25 | 26 | import java.util.List; 27 | 28 | /** 29 | * 30 | * @author mike wakerly (opensource@hoho.com) 31 | */ 32 | public interface UsbSerialDriver { 33 | 34 | /** 35 | * Returns the raw {@link UsbDevice} backing this port. 36 | * 37 | * @return the device 38 | */ 39 | public UsbDevice getDevice(); 40 | 41 | /** 42 | * Returns all available ports for this device. This list must have at least 43 | * one entry. 44 | * 45 | * @return the ports 46 | */ 47 | public List getPorts(); 48 | } 49 | -------------------------------------------------------------------------------- /test/rfc2217_server.diff: -------------------------------------------------------------------------------- 1 | *** /n/archiv/python/rfc2217_server.py 2018-03-10 09:02:07.613771600 +0100 2 | --- rfc2217_server.py 2018-03-09 20:57:44.933717100 +0100 3 | *************** 4 | *** 26,31 **** 5 | --- 26,32 ---- 6 | self, 7 | logger=logging.getLogger('rfc2217.server') if debug else None) 8 | self.log = logging.getLogger('redirector') 9 | + self.dlog = logging.getLogger('data') 10 | 11 | def statusline_poller(self): 12 | self.log.debug('status line poll thread started') 13 | *************** 14 | *** 55,60 **** 15 | --- 56,62 ---- 16 | try: 17 | data = self.serial.read(self.serial.in_waiting or 1) 18 | if data: 19 | + self.dlog.debug("serial read: "+data.encode('hex')) 20 | # escape outgoing data when needed (Telnet IAC (0xff) character) 21 | self.write(b''.join(self.rfc2217.escape(data))) 22 | except socket.error as msg: 23 | *************** 24 | *** 76,81 **** 25 | --- 78,84 ---- 26 | data = self.socket.recv(1024) 27 | if not data: 28 | break 29 | + self.dlog.debug("socket read: "+data.encode('hex')) 30 | self.serial.write(b''.join(self.rfc2217.filter(data))) 31 | except socket.error as msg: 32 | self.log.error('{}'.format(msg)) 33 | *************** 34 | *** 132,137 **** 35 | --- 135,141 ---- 36 | logging.basicConfig(level=logging.INFO) 37 | #~ logging.getLogger('root').setLevel(logging.INFO) 38 | logging.getLogger('rfc2217').setLevel(level) 39 | + logging.getLogger('data').setLevel(level) 40 | 41 | # connect to serial port 42 | ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True) 43 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 25 | 26 | 35 | 36 | 43 | 44 | 49 | 50 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/layout/serial_console.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 15 | 20 | 21 | 26 | 27 | 28 | 33 | 34 | 40 | 41 | 46 | 47 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge/arduino_leonardo_bridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | bridge USB-serial to hardware-serial 3 | 4 | for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro) 5 | hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB 6 | 7 | see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino 8 | -> CDC.cpp|HardwareSerial.cpp for serial implementation details 9 | 10 | this sketch is mainly for demonstration / test of CDC communication 11 | performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet 12 | */ 13 | 14 | uint32_t baud = 9600; 15 | uint8_t databits = 8; 16 | uint8_t stopbits = 1; 17 | uint8_t parity = 0; 18 | 19 | void setup() { 20 | Serial.begin(baud); // USB 21 | Serial1.begin(baud, SERIAL_8N1); 22 | } 23 | 24 | void loop() { 25 | // show USB connected state 26 | if (Serial) TXLED1; 27 | else TXLED0; 28 | 29 | // configure hardware serial 30 | if (Serial.baud() != baud || 31 | Serial.numbits() != databits || 32 | Serial.stopbits() != stopbits || 33 | Serial.paritytype() != parity) { 34 | baud = Serial.baud(); 35 | databits = Serial.numbits(); 36 | stopbits = Serial.stopbits(); 37 | parity = Serial.paritytype(); 38 | uint8_t config = 0; // ucsrc register 39 | switch (databits) { 40 | case 5: break; 41 | case 6: config |= 2; break; 42 | case 7: config |= 4; break; 43 | case 8: config |= 6; break; 44 | default: config |= 6; 45 | } 46 | switch (stopbits) { 47 | case 2: config |= 8; 48 | // 1.5 stopbits not supported 49 | } 50 | switch (parity) { 51 | case 1: config |= 0x30; break; // odd 52 | case 2: config |= 0x20; break; // even 53 | // mark, space not supported 54 | } 55 | Serial1.end(); 56 | Serial1.begin(baud, config); 57 | } 58 | 59 | // bridge 60 | if (Serial.available() > 0) 61 | Serial1.write(Serial.read()); 62 | if (Serial1.available() > 0) 63 | Serial.write(Serial1.read()); 64 | } 65 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | /** 25 | * Registry of USB vendor/product ID constants. 26 | * 27 | * Culled from various sources; see 28 | * usb.ids for one listing. 29 | * 30 | * @author mike wakerly (opensource@hoho.com) 31 | */ 32 | public final class UsbId { 33 | 34 | public static final int VENDOR_FTDI = 0x0403; 35 | public static final int FTDI_FT232R = 0x6001; 36 | public static final int FTDI_FT2232H = 0x6010; 37 | public static final int FTDI_FT4232H = 0x6011; 38 | public static final int FTDI_FT232H = 0x6014; 39 | public static final int FTDI_FT231X = 0x6015; 40 | 41 | public static final int VENDOR_ATMEL = 0x03EB; 42 | public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044; 43 | 44 | public static final int VENDOR_ARDUINO = 0x2341; 45 | public static final int ARDUINO_UNO = 0x0001; 46 | public static final int ARDUINO_MEGA_2560 = 0x0010; 47 | public static final int ARDUINO_SERIAL_ADAPTER = 0x003b; 48 | public static final int ARDUINO_MEGA_ADK = 0x003f; 49 | public static final int ARDUINO_MEGA_2560_R3 = 0x0042; 50 | public static final int ARDUINO_UNO_R3 = 0x0043; 51 | public static final int ARDUINO_MEGA_ADK_R3 = 0x0044; 52 | public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044; 53 | public static final int ARDUINO_LEONARDO = 0x8036; 54 | public static final int ARDUINO_MICRO = 0x8037; 55 | 56 | public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0; 57 | public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483; 58 | 59 | public static final int VENDOR_LEAFLABS = 0x1eaf; 60 | public static final int LEAFLABS_MAPLE = 0x0004; 61 | 62 | public static final int VENDOR_SILABS = 0x10c4; 63 | public static final int SILABS_CP2102 = 0xea60; 64 | public static final int SILABS_CP2105 = 0xea70; 65 | public static final int SILABS_CP2108 = 0xea71; 66 | public static final int SILABS_CP2110 = 0xea80; 67 | 68 | public static final int VENDOR_PROLIFIC = 0x067b; 69 | public static final int PROLIFIC_PL2303 = 0x2303; 70 | 71 | public static final int VENDOR_QINHENG = 0x1a86; 72 | public static final int QINHENG_HL340 = 0x7523; 73 | 74 | // at www.linux-usb.org/usb.ids listed for NXP/LPC1768, but all processors supported by ARM mbed DAPLink firmware report these ids 75 | public static final int VENDOR_ARM = 0x0d28; 76 | public static final int ARM_MBED = 0x0204; 77 | 78 | private UsbId() { 79 | throw new IllegalAccessError("Non-instantiable class."); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProbeTable.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.util.Pair; 25 | 26 | import java.lang.reflect.InvocationTargetException; 27 | import java.lang.reflect.Method; 28 | import java.util.LinkedHashMap; 29 | import java.util.Map; 30 | 31 | /** 32 | * Maps (vendor id, product id) pairs to the corresponding serial driver. 33 | * 34 | * @author mike wakerly (opensource@hoho.com) 35 | */ 36 | public class ProbeTable { 37 | 38 | private final Map, Class> mProbeTable = 39 | new LinkedHashMap, Class>(); 40 | 41 | /** 42 | * Adds or updates a (vendor, product) pair in the table. 43 | * 44 | * @param vendorId the USB vendor id 45 | * @param productId the USB product id 46 | * @param driverClass the driver class responsible for this pair 47 | * @return {@code this}, for chaining 48 | */ 49 | public ProbeTable addProduct(int vendorId, int productId, 50 | Class driverClass) { 51 | mProbeTable.put(Pair.create(vendorId, productId), driverClass); 52 | return this; 53 | } 54 | 55 | /** 56 | * Internal method to add all supported products from 57 | * {@code getSupportedProducts} static method. 58 | * 59 | * @param driverClass 60 | * @return 61 | */ 62 | @SuppressWarnings("unchecked") 63 | ProbeTable addDriver(Class driverClass) { 64 | final Method method; 65 | 66 | try { 67 | method = driverClass.getMethod("getSupportedDevices"); 68 | } catch (SecurityException e) { 69 | throw new RuntimeException(e); 70 | } catch (NoSuchMethodException e) { 71 | throw new RuntimeException(e); 72 | } 73 | 74 | final Map devices; 75 | try { 76 | devices = (Map) method.invoke(null); 77 | } catch (IllegalArgumentException e) { 78 | throw new RuntimeException(e); 79 | } catch (IllegalAccessException e) { 80 | throw new RuntimeException(e); 81 | } catch (InvocationTargetException e) { 82 | throw new RuntimeException(e); 83 | } 84 | 85 | for (Map.Entry entry : devices.entrySet()) { 86 | final int vendorId = entry.getKey().intValue(); 87 | for (int productId : entry.getValue()) { 88 | addProduct(vendorId, productId, driverClass); 89 | } 90 | } 91 | 92 | return this; 93 | } 94 | 95 | /** 96 | * Returns the driver for the given (vendor, product) pair, or {@code null} 97 | * if no match. 98 | * 99 | * @param vendorId the USB vendor id 100 | * @param productId the USB product id 101 | * @return the driver class matching this pair, or {@code null} 102 | */ 103 | public Class findDriver(int vendorId, int productId) { 104 | final Pair pair = Pair.create(vendorId, productId); 105 | return mProbeTable.get(pair); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialProber.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDevice; 25 | import android.hardware.usb.UsbManager; 26 | 27 | import java.lang.reflect.Constructor; 28 | import java.lang.reflect.InvocationTargetException; 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | /** 33 | * 34 | * @author mike wakerly (opensource@hoho.com) 35 | */ 36 | public class UsbSerialProber { 37 | 38 | private final ProbeTable mProbeTable; 39 | 40 | public UsbSerialProber(ProbeTable probeTable) { 41 | mProbeTable = probeTable; 42 | } 43 | 44 | public static UsbSerialProber getDefaultProber() { 45 | return new UsbSerialProber(getDefaultProbeTable()); 46 | } 47 | 48 | public static ProbeTable getDefaultProbeTable() { 49 | final ProbeTable probeTable = new ProbeTable(); 50 | probeTable.addDriver(CdcAcmSerialDriver.class); 51 | probeTable.addDriver(Cp21xxSerialDriver.class); 52 | probeTable.addDriver(FtdiSerialDriver.class); 53 | probeTable.addDriver(ProlificSerialDriver.class); 54 | probeTable.addDriver(Ch34xSerialDriver.class); 55 | return probeTable; 56 | } 57 | 58 | /** 59 | * Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers} 60 | * from the currently-attached {@link UsbDevice} hierarchy. This method does 61 | * not require permission from the Android USB system, since it does not 62 | * open any of the devices. 63 | * 64 | * @param usbManager 65 | * @return a list, possibly empty, of all compatible drivers 66 | */ 67 | public List findAllDrivers(final UsbManager usbManager) { 68 | final List result = new ArrayList(); 69 | 70 | for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) { 71 | final UsbSerialDriver driver = probeDevice(usbDevice); 72 | if (driver != null) { 73 | result.add(driver); 74 | } 75 | } 76 | return result; 77 | } 78 | 79 | /** 80 | * Probes a single device for a compatible driver. 81 | * 82 | * @param usbDevice the usb device to probe 83 | * @return a new {@link UsbSerialDriver} compatible with this device, or 84 | * {@code null} if none available. 85 | */ 86 | public UsbSerialDriver probeDevice(final UsbDevice usbDevice) { 87 | final int vendorId = usbDevice.getVendorId(); 88 | final int productId = usbDevice.getProductId(); 89 | 90 | final Class driverClass = 91 | mProbeTable.findDriver(vendorId, productId); 92 | if (driverClass != null) { 93 | final UsbSerialDriver driver; 94 | try { 95 | final Constructor ctor = 96 | driverClass.getConstructor(UsbDevice.class); 97 | driver = ctor.newInstance(usbDevice); 98 | } catch (NoSuchMethodException e) { 99 | throw new RuntimeException(e); 100 | } catch (IllegalArgumentException e) { 101 | throw new RuntimeException(e); 102 | } catch (InstantiationException e) { 103 | throw new RuntimeException(e); 104 | } catch (IllegalAccessException e) { 105 | throw new RuntimeException(e); 106 | } catch (InvocationTargetException e) { 107 | throw new RuntimeException(e); 108 | } 109 | return driver; 110 | } 111 | return null; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/HexDump.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hoho.android.usbserial.util; 18 | 19 | /** 20 | * Clone of Android's HexDump class, for use in debugging. Cosmetic changes 21 | * only. 22 | */ 23 | public class HexDump { 24 | private final static char[] HEX_DIGITS = { 25 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 26 | }; 27 | 28 | public static String dumpHexString(byte[] array) { 29 | return dumpHexString(array, 0, array.length); 30 | } 31 | 32 | public static String dumpHexString(byte[] array, int offset, int length) { 33 | StringBuilder result = new StringBuilder(); 34 | 35 | byte[] line = new byte[16]; 36 | int lineIndex = 0; 37 | 38 | result.append("\n0x"); 39 | result.append(toHexString(offset)); 40 | 41 | for (int i = offset; i < offset + length; i++) { 42 | if (lineIndex == 16) { 43 | result.append(" "); 44 | 45 | for (int j = 0; j < 16; j++) { 46 | if (line[j] > ' ' && line[j] < '~') { 47 | result.append(new String(line, j, 1)); 48 | } else { 49 | result.append("."); 50 | } 51 | } 52 | 53 | result.append("\n0x"); 54 | result.append(toHexString(i)); 55 | lineIndex = 0; 56 | } 57 | 58 | byte b = array[i]; 59 | result.append(" "); 60 | result.append(HEX_DIGITS[(b >>> 4) & 0x0F]); 61 | result.append(HEX_DIGITS[b & 0x0F]); 62 | 63 | line[lineIndex++] = b; 64 | } 65 | 66 | if (lineIndex != 16) { 67 | int count = (16 - lineIndex) * 3; 68 | count++; 69 | for (int i = 0; i < count; i++) { 70 | result.append(" "); 71 | } 72 | 73 | for (int i = 0; i < lineIndex; i++) { 74 | if (line[i] > ' ' && line[i] < '~') { 75 | result.append(new String(line, i, 1)); 76 | } else { 77 | result.append("."); 78 | } 79 | } 80 | } 81 | 82 | return result.toString(); 83 | } 84 | 85 | public static String toHexString(byte b) { 86 | return toHexString(toByteArray(b)); 87 | } 88 | 89 | public static String toHexString(byte[] array) { 90 | return toHexString(array, 0, array.length); 91 | } 92 | 93 | public static String toHexString(byte[] array, int offset, int length) { 94 | char[] buf = new char[length * 2]; 95 | 96 | int bufIndex = 0; 97 | for (int i = offset; i < offset + length; i++) { 98 | byte b = array[i]; 99 | buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; 100 | buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; 101 | } 102 | 103 | return new String(buf); 104 | } 105 | 106 | public static String toHexString(int i) { 107 | return toHexString(toByteArray(i)); 108 | } 109 | 110 | public static String toHexString(short i) { 111 | return toHexString(toByteArray(i)); 112 | } 113 | 114 | public static byte[] toByteArray(byte b) { 115 | byte[] array = new byte[1]; 116 | array[0] = b; 117 | return array; 118 | } 119 | 120 | public static byte[] toByteArray(int i) { 121 | byte[] array = new byte[4]; 122 | 123 | array[3] = (byte) (i & 0xFF); 124 | array[2] = (byte) ((i >> 8) & 0xFF); 125 | array[1] = (byte) ((i >> 16) & 0xFF); 126 | array[0] = (byte) ((i >> 24) & 0xFF); 127 | 128 | return array; 129 | } 130 | 131 | public static byte[] toByteArray(short i) { 132 | byte[] array = new byte[2]; 133 | 134 | array[1] = (byte) (i & 0xFF); 135 | array[0] = (byte) ((i >> 8) & 0xFF); 136 | 137 | return array; 138 | } 139 | 140 | private static int toByte(char c) { 141 | if (c >= '0' && c <= '9') 142 | return (c - '0'); 143 | if (c >= 'A' && c <= 'F') 144 | return (c - 'A' + 10); 145 | if (c >= 'a' && c <= 'f') 146 | return (c - 'a' + 10); 147 | 148 | throw new RuntimeException("Invalid hex char '" + c + "'"); 149 | } 150 | 151 | public static byte[] hexStringToByteArray(String hexString) { 152 | int length = hexString.length(); 153 | byte[] buffer = new byte[length / 2]; 154 | 155 | for (int i = 0; i < length; i += 2) { 156 | buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString 157 | .charAt(i + 1))); 158 | } 159 | 160 | return buffer; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDevice; 25 | import android.hardware.usb.UsbDeviceConnection; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * A base class shared by several driver implementations. 31 | * 32 | * @author mike wakerly (opensource@hoho.com) 33 | */ 34 | abstract class CommonUsbSerialPort implements UsbSerialPort { 35 | 36 | public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024; 37 | public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; 38 | 39 | protected final UsbDevice mDevice; 40 | protected final int mPortNumber; 41 | 42 | // non-null when open() 43 | protected UsbDeviceConnection mConnection = null; 44 | 45 | protected final Object mReadBufferLock = new Object(); 46 | protected final Object mWriteBufferLock = new Object(); 47 | 48 | /** Internal read buffer. Guarded by {@link #mReadBufferLock}. */ 49 | protected byte[] mReadBuffer; 50 | 51 | /** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */ 52 | protected byte[] mWriteBuffer; 53 | 54 | public CommonUsbSerialPort(UsbDevice device, int portNumber) { 55 | mDevice = device; 56 | mPortNumber = portNumber; 57 | 58 | mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE]; 59 | mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE]; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return String.format("<%s device_name=%s device_id=%s port_number=%s>", 65 | getClass().getSimpleName(), mDevice.getDeviceName(), 66 | mDevice.getDeviceId(), mPortNumber); 67 | } 68 | 69 | /** 70 | * Returns the currently-bound USB device. 71 | * 72 | * @return the device 73 | */ 74 | public final UsbDevice getDevice() { 75 | return mDevice; 76 | } 77 | 78 | @Override 79 | public int getPortNumber() { 80 | return mPortNumber; 81 | } 82 | 83 | /** 84 | * Returns the device serial number 85 | * @return serial number 86 | */ 87 | @Override 88 | public String getSerial() { 89 | return mConnection.getSerial(); 90 | } 91 | 92 | /** 93 | * Sets the size of the internal buffer used to exchange data with the USB 94 | * stack for read operations. Most users should not need to change this. 95 | * 96 | * @param bufferSize the size in bytes 97 | */ 98 | public final void setReadBufferSize(int bufferSize) { 99 | synchronized (mReadBufferLock) { 100 | if (bufferSize == mReadBuffer.length) { 101 | return; 102 | } 103 | mReadBuffer = new byte[bufferSize]; 104 | } 105 | } 106 | 107 | /** 108 | * Sets the size of the internal buffer used to exchange data with the USB 109 | * stack for write operations. Most users should not need to change this. 110 | * 111 | * @param bufferSize the size in bytes 112 | */ 113 | public final void setWriteBufferSize(int bufferSize) { 114 | synchronized (mWriteBufferLock) { 115 | if (bufferSize == mWriteBuffer.length) { 116 | return; 117 | } 118 | mWriteBuffer = new byte[bufferSize]; 119 | } 120 | } 121 | 122 | @Override 123 | public abstract void open(UsbDeviceConnection connection) throws IOException; 124 | 125 | @Override 126 | public abstract void close() throws IOException; 127 | 128 | @Override 129 | public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException; 130 | 131 | @Override 132 | public abstract int write(final byte[] src, final int timeoutMillis) throws IOException; 133 | 134 | @Override 135 | public abstract void setParameters( 136 | int baudRate, int dataBits, int stopBits, int parity) throws IOException; 137 | 138 | @Override 139 | public abstract boolean getCD() throws IOException; 140 | 141 | @Override 142 | public abstract boolean getCTS() throws IOException; 143 | 144 | @Override 145 | public abstract boolean getDSR() throws IOException; 146 | 147 | @Override 148 | public abstract boolean getDTR() throws IOException; 149 | 150 | @Override 151 | public abstract void setDTR(boolean value) throws IOException; 152 | 153 | @Override 154 | public abstract boolean getRI() throws IOException; 155 | 156 | @Override 157 | public abstract boolean getRTS() throws IOException; 158 | 159 | @Override 160 | public abstract void setRTS(boolean value) throws IOException; 161 | 162 | @Override 163 | public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException { 164 | return !flushReadBuffers && !flushWriteBuffers; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.util; 23 | 24 | import android.hardware.usb.UsbRequest; 25 | import android.util.Log; 26 | 27 | import com.hoho.android.usbserial.driver.UsbSerialPort; 28 | 29 | import java.io.IOException; 30 | import java.nio.ByteBuffer; 31 | 32 | /** 33 | * Utility class which services a {@link UsbSerialPort} in its {@link #run()} 34 | * method. 35 | * 36 | * @author mike wakerly (opensource@hoho.com) 37 | */ 38 | public class SerialInputOutputManager implements Runnable { 39 | 40 | private static final String TAG = SerialInputOutputManager.class.getSimpleName(); 41 | private static final boolean DEBUG = true; 42 | 43 | private static final int READ_WAIT_MILLIS = 200; 44 | private static final int BUFSIZ = 4096; 45 | 46 | private final UsbSerialPort mDriver; 47 | 48 | private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ); 49 | 50 | // Synchronized by 'mWriteBuffer' 51 | private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ); 52 | 53 | private enum State { 54 | STOPPED, 55 | RUNNING, 56 | STOPPING 57 | } 58 | 59 | // Synchronized by 'this' 60 | private State mState = State.STOPPED; 61 | 62 | // Synchronized by 'this' 63 | private Listener mListener; 64 | 65 | public interface Listener { 66 | /** 67 | * Called when new incoming data is available. 68 | */ 69 | public void onNewData(byte[] data); 70 | 71 | /** 72 | * Called when {@link SerialInputOutputManager#run()} aborts due to an 73 | * error. 74 | */ 75 | public void onRunError(Exception e); 76 | } 77 | 78 | /** 79 | * Creates a new instance with no listener. 80 | */ 81 | public SerialInputOutputManager(UsbSerialPort driver) { 82 | this(driver, null); 83 | } 84 | 85 | /** 86 | * Creates a new instance with the provided listener. 87 | */ 88 | public SerialInputOutputManager(UsbSerialPort driver, Listener listener) { 89 | mDriver = driver; 90 | mListener = listener; 91 | } 92 | 93 | public synchronized void setListener(Listener listener) { 94 | mListener = listener; 95 | } 96 | 97 | public synchronized Listener getListener() { 98 | return mListener; 99 | } 100 | 101 | public void writeAsync(byte[] data) { 102 | synchronized (mWriteBuffer) { 103 | mWriteBuffer.put(data); 104 | } 105 | } 106 | 107 | public synchronized void stop() { 108 | if (getState() == State.RUNNING) { 109 | Log.i(TAG, "Stop requested"); 110 | mState = State.STOPPING; 111 | } 112 | } 113 | 114 | private synchronized State getState() { 115 | return mState; 116 | } 117 | 118 | /** 119 | * Continuously services the read and write buffers until {@link #stop()} is 120 | * called, or until a driver exception is raised. 121 | * 122 | * NOTE(mikey): Uses inefficient read/write-with-timeout. 123 | */ 124 | @Override 125 | public void run() { 126 | synchronized (this) { 127 | if (getState() != State.STOPPED) { 128 | throw new IllegalStateException("Already running."); 129 | } 130 | mState = State.RUNNING; 131 | } 132 | 133 | Log.i(TAG, "Running .."); 134 | try { 135 | while (true) { 136 | if (getState() != State.RUNNING) { 137 | Log.i(TAG, "Stopping mState=" + getState()); 138 | break; 139 | } 140 | step(); 141 | } 142 | } catch (Exception e) { 143 | Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e); 144 | final Listener listener = getListener(); 145 | if (listener != null) { 146 | listener.onRunError(e); 147 | } 148 | } finally { 149 | synchronized (this) { 150 | mState = State.STOPPED; 151 | Log.i(TAG, "Stopped."); 152 | } 153 | } 154 | } 155 | 156 | private void step() throws IOException { 157 | // Handle incoming data. 158 | int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS); 159 | if (len > 0) { 160 | if (DEBUG) Log.d(TAG, "Read data len=" + len); 161 | final Listener listener = getListener(); 162 | if (listener != null) { 163 | final byte[] data = new byte[len]; 164 | mReadBuffer.get(data, 0, len); 165 | listener.onNewData(data); 166 | } 167 | mReadBuffer.clear(); 168 | } 169 | 170 | // Handle outgoing data. 171 | byte[] outBuff = null; 172 | synchronized (mWriteBuffer) { 173 | len = mWriteBuffer.position(); 174 | if (len > 0) { 175 | outBuff = new byte[len]; 176 | mWriteBuffer.rewind(); 177 | mWriteBuffer.get(outBuff, 0, len); 178 | mWriteBuffer.clear(); 179 | } 180 | } 181 | if (outBuff != null) { 182 | if (DEBUG) { 183 | Log.d(TAG, "Writing data len=" + len); 184 | } 185 | mDriver.write(outBuff, READ_WAIT_MILLIS); 186 | } 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Jitpack](https://jitpack.io/v/mik3y/usb-serial-for-android.svg)](https://jitpack.io/#mik3y/usb-serial-for-android) 2 | [![Codacy](https://api.codacy.com/project/badge/Grade/4d528e82e35d42d49f659e9b93a9c77d)](https://www.codacy.com/manual/kai-morich/usb-serial-for-android-mik3y?utm_source=github.com&utm_medium=referral&utm_content=mik3y/usb-serial-for-android&utm_campaign=Badge_Grade) 3 | 4 | --- 5 | > **Note:** all changes in this fork have been merged to the original repository. Please use [mik3y/usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android) 6 | --- 7 | 8 | # usb-serial-for-android 9 | 10 | This is a driver library for communication with Arduinos and other USB serial hardware on 11 | Android, using the 12 | [Android USB Host Mode (OTG)](http://developer.android.com/guide/topics/connectivity/usb/host.html) 13 | available since Android 3.1 and working reliably since Android 4.2. 14 | 15 | No root access, ADK, or special kernel drivers are required; all drivers are implemented in 16 | Java. You get a raw serial port with `read()`, `write()`, and other basic 17 | functions for use with your own protocols. 18 | 19 | ## Quick Start 20 | 21 | **1.** Add library to your project: 22 | 23 | Add jitpack.io repository to your root build.gradle: 24 | ```gradle 25 | allprojects { 26 | repositories { 27 | ... 28 | maven { url 'https://jitpack.io' } 29 | } 30 | } 31 | ``` 32 | Add library to dependencies 33 | ```gradle 34 | dependencies { 35 | implementation 'com.github.mik3y:usb-serial-for-android:Tag' 36 | } 37 | ``` 38 | 39 | **2.** Copy [device_filter.xml](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples/src/main/res/xml/device_filter.xml) to your project's `res/xml/` directory. 40 | 41 | **3.** Configure your `AndroidManifest.xml` to notify your app when a device is attached (see [Android USB Host documentation](http://developer.android.com/guide/topics/connectivity/usb/host.html#discovering-d) for help). 42 | 43 | ```xml 44 | 47 | 48 | 49 | 50 | 53 | 54 | ``` 55 | 56 | **4.** Use it! Example code snippet: 57 | 58 | ```java 59 | // Find all available drivers from attached devices. 60 | UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); 61 | List availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); 62 | if (availableDrivers.isEmpty()) { 63 | return; 64 | } 65 | 66 | // Open a connection to the first available driver. 67 | UsbSerialDriver driver = availableDrivers.get(0); 68 | UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); 69 | if (connection == null) { 70 | // You probably need to call UsbManager.requestPermission(driver.getDevice(), ..) 71 | return; 72 | } 73 | 74 | // Read some data! Most have just one port (port 0). 75 | UsbSerialPort port = driver.getPorts().get(0); 76 | try { 77 | port.open(connection); 78 | port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); 79 | 80 | byte buffer[] = new byte[16]; 81 | int numBytesRead = port.read(buffer, 1000); 82 | Log.d(TAG, "Read " + numBytesRead + " bytes."); 83 | } catch (IOException e) { 84 | // Deal with error. 85 | } finally { 86 | port.close(); 87 | } 88 | ``` 89 | 90 | For a simple example, see the 91 | [UsbSerialExamples project](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples) 92 | in git, which is a simple application for reading and showing serial data. 93 | 94 | For a more complete example, see separate github project 95 | [SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal) 96 | 97 | A [simple Arduino application](https://github.com/mik3y/usb-serial-for-android/blob/master/arduino) 98 | is also available which can be used for testing. 99 | 100 | ## Probing for Unrecognized Devices 101 | 102 | Sometimes you may need to do a little extra work to support devices which 103 | usb-serial-for-android doesn't (yet) know about -- but which you know to be 104 | compatible with one of the built-in drivers. This may be the case for a brand 105 | new device or for one using a custom VID/PID pair. 106 | 107 | UsbSerialProber is a class to help you find and instantiate compatible 108 | UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use 109 | the default prober returned by ``UsbSerialProber.getDefaultProber()``, which 110 | uses the built-in list of well-known VIDs and PIDs that are supported by our 111 | drivers. 112 | 113 | To use your own set of rules, create and use a custom prober: 114 | 115 | ```java 116 | // Probe for our custom CDC devices, which use VID 0x1234 117 | // and PIDS 0x0001 and 0x0002. 118 | ProbeTable customTable = new ProbeTable(); 119 | customTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class); 120 | customTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class); 121 | 122 | UsbSerialProber prober = new UsbSerialProber(customTable); 123 | List drivers = prober.findAllDrivers(usbManager); 124 | // ... 125 | ``` 126 | 127 | Of course, nothing requires you to use UsbSerialProber at all: you can 128 | instantiate driver classes directly if you know what you're doing; just supply 129 | a compatible UsbDevice. 130 | 131 | ## Compatible Devices 132 | 133 | This library supports USB to serial converter chips: 134 | * FTDI FT232, FT2232, ... 135 | * Prolific PL2303 136 | * Silabs CP2102, CP2105, ... 137 | * Qinheng CH340 138 | 139 | and devices implementing the CDC/ACM protocol like 140 | * Arduino using ATmega32U4 141 | * Digispark using V-USB software USB 142 | * BBC micro:bit using ARM mbed DAPLink firmware 143 | * ... 144 | 145 | ## Author, License, and Copyright 146 | 147 | usb-serial-for-android is written and maintained by *mike wakerly* and *kai morich* 148 | 149 | This library is licensed under *LGPL Version 2.1*. Please see LICENSE.txt for the 150 | complete license. 151 | 152 | Copyright 2011-2012, Google Inc. All Rights Reserved. 153 | 154 | Portions of this library are based on [libftdi](http://www.intra2net.com/en/developer/libftdi). 155 | Please see FtdiSerialDriver.java for more information. 156 | 157 | ## Help & Discussion 158 | 159 | For common problems, see the 160 | [Troubleshooting](https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting) 161 | wiki page. 162 | 163 | Are you using the library? Add your project to 164 | [ProjectsUsingUsbSerialForAndroid](https://github.com/mik3y/usb-serial-for-android/wiki/Projects-Using-usb-serial-for-android). 165 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/DeviceListActivity.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.examples; 23 | 24 | import android.app.Activity; 25 | import android.content.Context; 26 | import android.hardware.usb.UsbDevice; 27 | import android.hardware.usb.UsbManager; 28 | import android.os.AsyncTask; 29 | import android.os.Bundle; 30 | import android.os.Handler; 31 | import android.os.Message; 32 | import android.os.SystemClock; 33 | import android.util.Log; 34 | import android.view.LayoutInflater; 35 | import android.view.View; 36 | import android.view.ViewGroup; 37 | import android.widget.AdapterView; 38 | import android.widget.ArrayAdapter; 39 | import android.widget.ListView; 40 | import android.widget.ProgressBar; 41 | import android.widget.TextView; 42 | import android.widget.TwoLineListItem; 43 | 44 | import com.hoho.android.usbserial.driver.UsbSerialDriver; 45 | import com.hoho.android.usbserial.driver.UsbSerialPort; 46 | import com.hoho.android.usbserial.driver.UsbSerialProber; 47 | import com.hoho.android.usbserial.util.HexDump; 48 | 49 | import java.util.ArrayList; 50 | import java.util.List; 51 | 52 | /** 53 | * Shows a {@link ListView} of available USB devices. 54 | * 55 | * @author mike wakerly (opensource@hoho.com) 56 | */ 57 | public class DeviceListActivity extends Activity { 58 | 59 | private final String TAG = DeviceListActivity.class.getSimpleName(); 60 | 61 | private UsbManager mUsbManager; 62 | private ListView mListView; 63 | private TextView mProgressBarTitle; 64 | private ProgressBar mProgressBar; 65 | 66 | private static final int MESSAGE_REFRESH = 101; 67 | private static final long REFRESH_TIMEOUT_MILLIS = 5000; 68 | 69 | private final Handler mHandler = new Handler() { 70 | @Override 71 | public void handleMessage(Message msg) { 72 | switch (msg.what) { 73 | case MESSAGE_REFRESH: 74 | refreshDeviceList(); 75 | mHandler.sendEmptyMessageDelayed(MESSAGE_REFRESH, REFRESH_TIMEOUT_MILLIS); 76 | break; 77 | default: 78 | super.handleMessage(msg); 79 | break; 80 | } 81 | } 82 | 83 | }; 84 | 85 | private List mEntries = new ArrayList(); 86 | private ArrayAdapter mAdapter; 87 | 88 | @Override 89 | public void onCreate(Bundle savedInstanceState) { 90 | super.onCreate(savedInstanceState); 91 | setContentView(R.layout.main); 92 | 93 | mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); 94 | mListView = (ListView) findViewById(R.id.deviceList); 95 | mProgressBar = (ProgressBar) findViewById(R.id.progressBar); 96 | mProgressBarTitle = (TextView) findViewById(R.id.progressBarTitle); 97 | 98 | mAdapter = new ArrayAdapter(this, 99 | android.R.layout.simple_expandable_list_item_2, mEntries) { 100 | @Override 101 | public View getView(int position, View convertView, ViewGroup parent) { 102 | final TwoLineListItem row; 103 | if (convertView == null){ 104 | final LayoutInflater inflater = 105 | (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 106 | row = (TwoLineListItem) inflater.inflate(android.R.layout.simple_list_item_2, null); 107 | } else { 108 | row = (TwoLineListItem) convertView; 109 | } 110 | 111 | final UsbSerialPort port = mEntries.get(position); 112 | final UsbSerialDriver driver = port.getDriver(); 113 | final UsbDevice device = driver.getDevice(); 114 | 115 | final String title = String.format("Vendor %s Product %s", 116 | HexDump.toHexString((short) device.getVendorId()), 117 | HexDump.toHexString((short) device.getProductId())); 118 | row.getText1().setText(title); 119 | 120 | final String subtitle = driver.getClass().getSimpleName(); 121 | row.getText2().setText(subtitle); 122 | 123 | return row; 124 | } 125 | 126 | }; 127 | mListView.setAdapter(mAdapter); 128 | 129 | mListView.setOnItemClickListener(new ListView.OnItemClickListener() { 130 | @Override 131 | public void onItemClick(AdapterView parent, View view, int position, long id) { 132 | Log.d(TAG, "Pressed item " + position); 133 | if (position >= mEntries.size()) { 134 | Log.w(TAG, "Illegal position."); 135 | return; 136 | } 137 | 138 | final UsbSerialPort port = mEntries.get(position); 139 | showConsoleActivity(port); 140 | } 141 | }); 142 | } 143 | 144 | @Override 145 | protected void onResume() { 146 | super.onResume(); 147 | mHandler.sendEmptyMessage(MESSAGE_REFRESH); 148 | } 149 | 150 | @Override 151 | protected void onPause() { 152 | super.onPause(); 153 | mHandler.removeMessages(MESSAGE_REFRESH); 154 | } 155 | 156 | private void refreshDeviceList() { 157 | showProgressBar(); 158 | 159 | new AsyncTask>() { 160 | @Override 161 | protected List doInBackground(Void... params) { 162 | Log.d(TAG, "Refreshing device list ..."); 163 | SystemClock.sleep(1000); 164 | 165 | final List drivers = 166 | UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager); 167 | 168 | final List result = new ArrayList(); 169 | for (final UsbSerialDriver driver : drivers) { 170 | final List ports = driver.getPorts(); 171 | Log.d(TAG, String.format("+ %s: %s port%s", 172 | driver, Integer.valueOf(ports.size()), ports.size() == 1 ? "" : "s")); 173 | result.addAll(ports); 174 | } 175 | 176 | return result; 177 | } 178 | 179 | @Override 180 | protected void onPostExecute(List result) { 181 | mEntries.clear(); 182 | mEntries.addAll(result); 183 | mAdapter.notifyDataSetChanged(); 184 | mProgressBarTitle.setText( 185 | String.format("%s device(s) found",Integer.valueOf(mEntries.size()))); 186 | hideProgressBar(); 187 | Log.d(TAG, "Done refreshing, " + mEntries.size() + " entries found."); 188 | } 189 | 190 | }.execute((Void) null); 191 | } 192 | 193 | private void showProgressBar() { 194 | mProgressBar.setVisibility(View.VISIBLE); 195 | mProgressBarTitle.setText(R.string.refreshing); 196 | } 197 | 198 | private void hideProgressBar() { 199 | mProgressBar.setVisibility(View.INVISIBLE); 200 | } 201 | 202 | private void showConsoleActivity(UsbSerialPort port) { 203 | SerialConsoleActivity.show(this, port); 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialPort.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDeviceConnection; 25 | import android.hardware.usb.UsbManager; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * Interface for a single serial port. 31 | * 32 | * @author mike wakerly (opensource@hoho.com) 33 | */ 34 | public interface UsbSerialPort { 35 | 36 | /** 5 data bits. */ 37 | public static final int DATABITS_5 = 5; 38 | 39 | /** 6 data bits. */ 40 | public static final int DATABITS_6 = 6; 41 | 42 | /** 7 data bits. */ 43 | public static final int DATABITS_7 = 7; 44 | 45 | /** 8 data bits. */ 46 | public static final int DATABITS_8 = 8; 47 | 48 | /** No flow control. */ 49 | public static final int FLOWCONTROL_NONE = 0; 50 | 51 | /** RTS/CTS input flow control. */ 52 | public static final int FLOWCONTROL_RTSCTS_IN = 1; 53 | 54 | /** RTS/CTS output flow control. */ 55 | public static final int FLOWCONTROL_RTSCTS_OUT = 2; 56 | 57 | /** XON/XOFF input flow control. */ 58 | public static final int FLOWCONTROL_XONXOFF_IN = 4; 59 | 60 | /** XON/XOFF output flow control. */ 61 | public static final int FLOWCONTROL_XONXOFF_OUT = 8; 62 | 63 | /** No parity. */ 64 | public static final int PARITY_NONE = 0; 65 | 66 | /** Odd parity. */ 67 | public static final int PARITY_ODD = 1; 68 | 69 | /** Even parity. */ 70 | public static final int PARITY_EVEN = 2; 71 | 72 | /** Mark parity. */ 73 | public static final int PARITY_MARK = 3; 74 | 75 | /** Space parity. */ 76 | public static final int PARITY_SPACE = 4; 77 | 78 | /** 1 stop bit. */ 79 | public static final int STOPBITS_1 = 1; 80 | 81 | /** 1.5 stop bits. */ 82 | public static final int STOPBITS_1_5 = 3; 83 | 84 | /** 2 stop bits. */ 85 | public static final int STOPBITS_2 = 2; 86 | 87 | public UsbSerialDriver getDriver(); 88 | 89 | /** 90 | * Port number within driver. 91 | */ 92 | public int getPortNumber(); 93 | 94 | /** 95 | * The serial number of the underlying UsbDeviceConnection, or {@code null}. 96 | */ 97 | public String getSerial(); 98 | 99 | /** 100 | * Opens and initializes the port. Upon success, caller must ensure that 101 | * {@link #close()} is eventually called. 102 | * 103 | * @param connection an open device connection, acquired with 104 | * {@link UsbManager#openDevice(android.hardware.usb.UsbDevice)} 105 | * @throws IOException on error opening or initializing the port. 106 | */ 107 | public void open(UsbDeviceConnection connection) throws IOException; 108 | 109 | /** 110 | * Closes the port. 111 | * 112 | * @throws IOException on error closing the port. 113 | */ 114 | public void close() throws IOException; 115 | 116 | /** 117 | * Reads as many bytes as possible into the destination buffer. 118 | * 119 | * @param dest the destination byte buffer 120 | * @param timeoutMillis the timeout for reading 121 | * @return the actual number of bytes read 122 | * @throws IOException if an error occurred during reading 123 | */ 124 | public int read(final byte[] dest, final int timeoutMillis) throws IOException; 125 | 126 | /** 127 | * Writes as many bytes as possible from the source buffer. 128 | * 129 | * @param src the source byte buffer 130 | * @param timeoutMillis the timeout for writing 131 | * @return the actual number of bytes written 132 | * @throws IOException if an error occurred during writing 133 | */ 134 | public int write(final byte[] src, final int timeoutMillis) throws IOException; 135 | 136 | /** 137 | * Sets various serial port parameters. 138 | * 139 | * @param baudRate baud rate as an integer, for example {@code 115200}. 140 | * @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6}, 141 | * {@link #DATABITS_7}, or {@link #DATABITS_8}. 142 | * @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or 143 | * {@link #STOPBITS_2}. 144 | * @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD}, 145 | * {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or 146 | * {@link #PARITY_SPACE}. 147 | * @throws IOException on error setting the port parameters 148 | */ 149 | public void setParameters( 150 | int baudRate, int dataBits, int stopBits, int parity) throws IOException; 151 | 152 | /** 153 | * Gets the CD (Carrier Detect) bit from the underlying UART. 154 | * 155 | * @return the current state, or {@code false} if not supported. 156 | * @throws IOException if an error occurred during reading 157 | */ 158 | public boolean getCD() throws IOException; 159 | 160 | /** 161 | * Gets the CTS (Clear To Send) bit from the underlying UART. 162 | * 163 | * @return the current state, or {@code false} if not supported. 164 | * @throws IOException if an error occurred during reading 165 | */ 166 | public boolean getCTS() throws IOException; 167 | 168 | /** 169 | * Gets the DSR (Data Set Ready) bit from the underlying UART. 170 | * 171 | * @return the current state, or {@code false} if not supported. 172 | * @throws IOException if an error occurred during reading 173 | */ 174 | public boolean getDSR() throws IOException; 175 | 176 | /** 177 | * Gets the DTR (Data Terminal Ready) bit from the underlying UART. 178 | * 179 | * @return the current state, or {@code false} if not supported. 180 | * @throws IOException if an error occurred during reading 181 | */ 182 | public boolean getDTR() throws IOException; 183 | 184 | /** 185 | * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if 186 | * supported. 187 | * 188 | * @param value the value to set 189 | * @throws IOException if an error occurred during writing 190 | */ 191 | public void setDTR(boolean value) throws IOException; 192 | 193 | /** 194 | * Gets the RI (Ring Indicator) bit from the underlying UART. 195 | * 196 | * @return the current state, or {@code false} if not supported. 197 | * @throws IOException if an error occurred during reading 198 | */ 199 | public boolean getRI() throws IOException; 200 | 201 | /** 202 | * Gets the RTS (Request To Send) bit from the underlying UART. 203 | * 204 | * @return the current state, or {@code false} if not supported. 205 | * @throws IOException if an error occurred during reading 206 | */ 207 | public boolean getRTS() throws IOException; 208 | 209 | /** 210 | * Sets the RTS (Request To Send) bit on the underlying UART, if 211 | * supported. 212 | * 213 | * @param value the value to set 214 | * @throws IOException if an error occurred during writing 215 | */ 216 | public void setRTS(boolean value) throws IOException; 217 | 218 | /** 219 | * Flush non-transmitted output data and / or non-read input data 220 | * @param flushRX {@code true} to flush non-transmitted output data 221 | * @param flushTX {@code true} to flush non-read input data 222 | * @return {@code true} if the operation was successful, or 223 | * {@code false} if the operation is not supported by the driver or device 224 | * @throws IOException if an error occurred during flush 225 | */ 226 | public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException; 227 | 228 | } 229 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/SerialConsoleActivity.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.examples; 23 | 24 | import android.app.Activity; 25 | import android.content.Context; 26 | import android.content.Intent; 27 | import android.hardware.usb.UsbDeviceConnection; 28 | import android.hardware.usb.UsbManager; 29 | import android.os.Bundle; 30 | import android.util.Log; 31 | import android.widget.CheckBox; 32 | import android.widget.CompoundButton; 33 | import android.widget.ScrollView; 34 | import android.widget.TextView; 35 | 36 | import com.hoho.android.usbserial.driver.UsbSerialPort; 37 | import com.hoho.android.usbserial.util.HexDump; 38 | import com.hoho.android.usbserial.util.SerialInputOutputManager; 39 | 40 | import java.io.IOException; 41 | import java.util.concurrent.ExecutorService; 42 | import java.util.concurrent.Executors; 43 | 44 | /** 45 | * Monitors a single {@link UsbSerialPort} instance, showing all data 46 | * received. 47 | * 48 | * @author mike wakerly (opensource@hoho.com) 49 | */ 50 | public class SerialConsoleActivity extends Activity { 51 | 52 | private final String TAG = SerialConsoleActivity.class.getSimpleName(); 53 | 54 | /** 55 | * Driver instance, passed in statically via 56 | * {@link #show(Context, UsbSerialPort)}. 57 | * 58 | *

59 | * This is a devious hack; it'd be cleaner to re-create the driver using 60 | * arguments passed in with the {@link #startActivity(Intent)} intent. We 61 | * can get away with it because both activities will run in the same 62 | * process, and this is a simple demo. 63 | */ 64 | private static UsbSerialPort sPort = null; 65 | 66 | private TextView mTitleTextView; 67 | private TextView mDumpTextView; 68 | private ScrollView mScrollView; 69 | private CheckBox chkDTR; 70 | private CheckBox chkRTS; 71 | 72 | private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); 73 | 74 | private SerialInputOutputManager mSerialIoManager; 75 | 76 | private final SerialInputOutputManager.Listener mListener = 77 | new SerialInputOutputManager.Listener() { 78 | 79 | @Override 80 | public void onRunError(Exception e) { 81 | Log.d(TAG, "Runner stopped."); 82 | } 83 | 84 | @Override 85 | public void onNewData(final byte[] data) { 86 | SerialConsoleActivity.this.runOnUiThread(new Runnable() { 87 | @Override 88 | public void run() { 89 | SerialConsoleActivity.this.updateReceivedData(data); 90 | } 91 | }); 92 | } 93 | }; 94 | 95 | @Override 96 | public void onCreate(Bundle savedInstanceState) { 97 | super.onCreate(savedInstanceState); 98 | setContentView(R.layout.serial_console); 99 | mTitleTextView = (TextView) findViewById(R.id.demoTitle); 100 | mDumpTextView = (TextView) findViewById(R.id.consoleText); 101 | mScrollView = (ScrollView) findViewById(R.id.demoScroller); 102 | chkDTR = (CheckBox) findViewById(R.id.checkBoxDTR); 103 | chkRTS = (CheckBox) findViewById(R.id.checkBoxRTS); 104 | 105 | chkDTR.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 106 | @Override 107 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 108 | try { 109 | sPort.setDTR(isChecked); 110 | }catch (IOException x){} 111 | } 112 | }); 113 | 114 | chkRTS.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 115 | @Override 116 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 117 | try { 118 | sPort.setRTS(isChecked); 119 | }catch (IOException x){} 120 | } 121 | }); 122 | 123 | } 124 | 125 | 126 | @Override 127 | protected void onPause() { 128 | super.onPause(); 129 | stopIoManager(); 130 | if (sPort != null) { 131 | try { 132 | sPort.close(); 133 | } catch (IOException e) { 134 | // Ignore. 135 | } 136 | sPort = null; 137 | } 138 | finish(); 139 | } 140 | 141 | void showStatus(TextView theTextView, String theLabel, boolean theValue){ 142 | String msg = theLabel + ": " + (theValue ? "enabled" : "disabled") + "\n"; 143 | theTextView.append(msg); 144 | } 145 | 146 | @Override 147 | protected void onResume() { 148 | super.onResume(); 149 | Log.d(TAG, "Resumed, port=" + sPort); 150 | if (sPort == null) { 151 | mTitleTextView.setText("No serial device."); 152 | } else { 153 | final UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); 154 | 155 | UsbDeviceConnection connection = usbManager.openDevice(sPort.getDriver().getDevice()); 156 | if (connection == null) { 157 | mTitleTextView.setText("Opening device failed"); 158 | return; 159 | } 160 | 161 | try { 162 | sPort.open(connection); 163 | sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); 164 | 165 | showStatus(mDumpTextView, "CD - Carrier Detect", sPort.getCD()); 166 | showStatus(mDumpTextView, "CTS - Clear To Send", sPort.getCTS()); 167 | showStatus(mDumpTextView, "DSR - Data Set Ready", sPort.getDSR()); 168 | showStatus(mDumpTextView, "DTR - Data Terminal Ready", sPort.getDTR()); 169 | showStatus(mDumpTextView, "DSR - Data Set Ready", sPort.getDSR()); 170 | showStatus(mDumpTextView, "RI - Ring Indicator", sPort.getRI()); 171 | showStatus(mDumpTextView, "RTS - Request To Send", sPort.getRTS()); 172 | 173 | } catch (IOException e) { 174 | Log.e(TAG, "Error setting up device: " + e.getMessage(), e); 175 | mTitleTextView.setText("Error opening device: " + e.getMessage()); 176 | try { 177 | sPort.close(); 178 | } catch (IOException e2) { 179 | // Ignore. 180 | } 181 | sPort = null; 182 | return; 183 | } 184 | mTitleTextView.setText("Serial device: " + sPort.getClass().getSimpleName()); 185 | } 186 | onDeviceStateChange(); 187 | } 188 | 189 | private void stopIoManager() { 190 | if (mSerialIoManager != null) { 191 | Log.i(TAG, "Stopping io manager .."); 192 | mSerialIoManager.stop(); 193 | mSerialIoManager = null; 194 | } 195 | } 196 | 197 | private void startIoManager() { 198 | if (sPort != null) { 199 | Log.i(TAG, "Starting io manager .."); 200 | mSerialIoManager = new SerialInputOutputManager(sPort, mListener); 201 | mExecutor.submit(mSerialIoManager); 202 | } 203 | } 204 | 205 | private void onDeviceStateChange() { 206 | stopIoManager(); 207 | startIoManager(); 208 | } 209 | 210 | private void updateReceivedData(byte[] data) { 211 | final String message = "Read " + data.length + " bytes: \n" 212 | + HexDump.dumpHexString(data) + "\n\n"; 213 | mDumpTextView.append(message); 214 | mScrollView.smoothScrollTo(0, mDumpTextView.getBottom()); 215 | } 216 | 217 | /** 218 | * Starts the activity, using the supplied driver instance. 219 | * 220 | * @param context 221 | * @param driver 222 | */ 223 | static void show(Context context, UsbSerialPort port) { 224 | sPort = port; 225 | final Intent intent = new Intent(context, SerialConsoleActivity.class); 226 | intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY); 227 | context.startActivity(intent); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2014 Andreas Butti 2 | * 3 | * This library is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU Lesser General Public 5 | * License as published by the Free Software Foundation; either 6 | * version 2.1 of the License, or (at your option) any later version. 7 | * 8 | * This library is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public 14 | * License along with this library; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 16 | * USA. 17 | * 18 | * Project home page: https://github.com/mik3y/usb-serial-for-android 19 | */ 20 | 21 | package com.hoho.android.usbserial.driver; 22 | 23 | import android.hardware.usb.UsbConstants; 24 | import android.hardware.usb.UsbDevice; 25 | import android.hardware.usb.UsbDeviceConnection; 26 | import android.hardware.usb.UsbEndpoint; 27 | import android.hardware.usb.UsbInterface; 28 | import android.hardware.usb.UsbRequest; 29 | import android.util.Log; 30 | 31 | import java.io.IOException; 32 | import java.nio.ByteBuffer; 33 | import java.util.Collections; 34 | import java.util.LinkedHashMap; 35 | import java.util.List; 36 | import java.util.Map; 37 | 38 | /** 39 | * Driver for CH340, maybe also working with CH341, but not tested 40 | * See http://wch-ic.com/product/usb/ch340.asp 41 | * 42 | * @author Andreas Butti 43 | */ 44 | public class Ch34xSerialDriver implements UsbSerialDriver { 45 | 46 | private static final String TAG = Ch34xSerialDriver.class.getSimpleName(); 47 | 48 | private final UsbDevice mDevice; 49 | private final UsbSerialPort mPort; 50 | 51 | private static final int LCR_ENABLE_RX = 0x80; 52 | private static final int LCR_ENABLE_TX = 0x40; 53 | private static final int LCR_MARK_SPACE = 0x20; 54 | private static final int LCR_PAR_EVEN = 0x10; 55 | private static final int LCR_ENABLE_PAR = 0x08; 56 | private static final int LCR_STOP_BITS_2 = 0x04; 57 | private static final int LCR_CS8 = 0x03; 58 | private static final int LCR_CS7 = 0x02; 59 | private static final int LCR_CS6 = 0x01; 60 | private static final int LCR_CS5 = 0x00; 61 | 62 | public Ch34xSerialDriver(UsbDevice device) { 63 | mDevice = device; 64 | mPort = new Ch340SerialPort(mDevice, 0); 65 | } 66 | 67 | @Override 68 | public UsbDevice getDevice() { 69 | return mDevice; 70 | } 71 | 72 | @Override 73 | public List getPorts() { 74 | return Collections.singletonList(mPort); 75 | } 76 | 77 | public class Ch340SerialPort extends CommonUsbSerialPort { 78 | 79 | private static final int USB_TIMEOUT_MILLIS = 5000; 80 | 81 | private final int DEFAULT_BAUD_RATE = 9600; 82 | 83 | private boolean dtr = false; 84 | private boolean rts = false; 85 | 86 | private UsbEndpoint mReadEndpoint; 87 | private UsbEndpoint mWriteEndpoint; 88 | private UsbRequest mUsbRequest; 89 | 90 | public Ch340SerialPort(UsbDevice device, int portNumber) { 91 | super(device, portNumber); 92 | } 93 | 94 | @Override 95 | public UsbSerialDriver getDriver() { 96 | return Ch34xSerialDriver.this; 97 | } 98 | 99 | @Override 100 | public void open(UsbDeviceConnection connection) throws IOException { 101 | if (mConnection != null) { 102 | throw new IOException("Already opened."); 103 | } 104 | 105 | mConnection = connection; 106 | boolean opened = false; 107 | try { 108 | for (int i = 0; i < mDevice.getInterfaceCount(); i++) { 109 | UsbInterface usbIface = mDevice.getInterface(i); 110 | if (!mConnection.claimInterface(usbIface, true)) { 111 | throw new IOException("Could not claim data interface."); 112 | } 113 | } 114 | 115 | UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1); 116 | for (int i = 0; i < dataIface.getEndpointCount(); i++) { 117 | UsbEndpoint ep = dataIface.getEndpoint(i); 118 | if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { 119 | if (ep.getDirection() == UsbConstants.USB_DIR_IN) { 120 | mReadEndpoint = ep; 121 | } else { 122 | mWriteEndpoint = ep; 123 | } 124 | } 125 | } 126 | 127 | initialize(); 128 | setBaudRate(DEFAULT_BAUD_RATE); 129 | 130 | opened = true; 131 | } finally { 132 | if (!opened) { 133 | try { 134 | close(); 135 | } catch (IOException e) { 136 | // Ignore IOExceptions during close() 137 | } 138 | } 139 | } 140 | } 141 | 142 | @Override 143 | public void close() throws IOException { 144 | if (mConnection == null) { 145 | throw new IOException("Already closed"); 146 | } 147 | synchronized (this) { 148 | if (mUsbRequest != null) 149 | mUsbRequest.cancel(); 150 | } 151 | try { 152 | mConnection.close(); 153 | } finally { 154 | mConnection = null; 155 | } 156 | } 157 | 158 | 159 | @Override 160 | public int read(byte[] dest, int timeoutMillis) throws IOException { 161 | final UsbRequest request = new UsbRequest(); 162 | try { 163 | request.initialize(mConnection, mReadEndpoint); 164 | final ByteBuffer buf = ByteBuffer.wrap(dest); 165 | if (!request.queue(buf, dest.length)) { 166 | throw new IOException("Error queueing request."); 167 | } 168 | mUsbRequest = request; 169 | final UsbRequest response = mConnection.requestWait(); 170 | synchronized (this) { 171 | mUsbRequest = null; 172 | } 173 | if (response == null) { 174 | throw new IOException("Null response"); 175 | } 176 | 177 | final int nread = buf.position(); 178 | if (nread > 0) { 179 | //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); 180 | return nread; 181 | } else { 182 | return 0; 183 | } 184 | } finally { 185 | mUsbRequest = null; 186 | request.close(); 187 | } 188 | } 189 | 190 | @Override 191 | public int write(byte[] src, int timeoutMillis) throws IOException { 192 | int offset = 0; 193 | 194 | while (offset < src.length) { 195 | final int writeLength; 196 | final int amtWritten; 197 | 198 | synchronized (mWriteBufferLock) { 199 | final byte[] writeBuffer; 200 | 201 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 202 | if (offset == 0) { 203 | writeBuffer = src; 204 | } else { 205 | // bulkTransfer does not support offsets, make a copy. 206 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 207 | writeBuffer = mWriteBuffer; 208 | } 209 | 210 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, 211 | timeoutMillis); 212 | } 213 | if (amtWritten <= 0) { 214 | throw new IOException("Error writing " + writeLength 215 | + " bytes at offset " + offset + " length=" + src.length); 216 | } 217 | 218 | Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); 219 | offset += amtWritten; 220 | } 221 | return offset; 222 | } 223 | 224 | private int controlOut(int request, int value, int index) { 225 | final int REQTYPE_HOST_TO_DEVICE = 0x41; 226 | return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, 227 | value, index, null, 0, USB_TIMEOUT_MILLIS); 228 | } 229 | 230 | 231 | private int controlIn(int request, int value, int index, byte[] buffer) { 232 | final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN; 233 | return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, 234 | value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS); 235 | } 236 | 237 | 238 | private void checkState(String msg, int request, int value, int[] expected) throws IOException { 239 | byte[] buffer = new byte[expected.length]; 240 | int ret = controlIn(request, value, 0, buffer); 241 | 242 | if (ret < 0) { 243 | throw new IOException("Faild send cmd [" + msg + "]"); 244 | } 245 | 246 | if (ret != expected.length) { 247 | throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]"); 248 | } 249 | 250 | for (int i = 0; i < expected.length; i++) { 251 | if (expected[i] == -1) { 252 | continue; 253 | } 254 | 255 | int current = buffer[i] & 0xff; 256 | if (expected[i] != current) { 257 | throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " bytes, but get 0x" + Integer.toHexString(current) + " [" + msg + "]"); 258 | } 259 | } 260 | } 261 | 262 | private void writeHandshakeByte() throws IOException { 263 | if (controlOut(0xa4, ~((dtr ? 1 << 5 : 0) | (rts ? 1 << 6 : 0)), 0) < 0) { 264 | throw new IOException("Faild to set handshake byte"); 265 | } 266 | } 267 | 268 | private void initialize() throws IOException { 269 | checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00}); 270 | 271 | if (controlOut(0xa1, 0, 0) < 0) { 272 | throw new IOException("init failed! #2"); 273 | } 274 | 275 | setBaudRate(DEFAULT_BAUD_RATE); 276 | 277 | checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00}); 278 | 279 | if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) { 280 | throw new IOException("init failed! #5"); 281 | } 282 | 283 | checkState("init #6", 0x95, 0x0706, new int[]{0xff, 0xee}); 284 | 285 | if (controlOut(0xa1, 0x501f, 0xd90a) < 0) { 286 | throw new IOException("init failed! #7"); 287 | } 288 | 289 | setBaudRate(DEFAULT_BAUD_RATE); 290 | 291 | writeHandshakeByte(); 292 | 293 | checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, 0xee}); 294 | } 295 | 296 | 297 | private void setBaudRate(int baudRate) throws IOException { 298 | final long CH341_BAUDBASE_FACTOR = 1532620800; 299 | final int CH341_BAUDBASE_DIVMAX = 3; 300 | 301 | long factor = CH341_BAUDBASE_FACTOR / baudRate; 302 | int divisor = CH341_BAUDBASE_DIVMAX; 303 | 304 | while ((factor > 0xfff0) && divisor > 0) { 305 | factor >>= 3; 306 | divisor--; 307 | } 308 | 309 | if (factor > 0xfff0) { 310 | throw new IOException("Baudrate " + baudRate + " not supported"); 311 | } 312 | 313 | factor = 0x10000 - factor; 314 | 315 | int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor)); 316 | if (ret < 0) { 317 | throw new IOException("Error setting baud rate. #1)"); 318 | } 319 | 320 | ret = controlOut(0x9a, 0x0f2c, (int) (factor & 0xff)); 321 | if (ret < 0) { 322 | throw new IOException("Error setting baud rate. #2"); 323 | } 324 | } 325 | 326 | @Override 327 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) 328 | throws IOException { 329 | setBaudRate(baudRate); 330 | 331 | int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX; 332 | 333 | switch (dataBits) { 334 | case DATABITS_5: 335 | lcr |= LCR_CS5; 336 | break; 337 | case DATABITS_6: 338 | lcr |= LCR_CS6; 339 | break; 340 | case DATABITS_7: 341 | lcr |= LCR_CS7; 342 | break; 343 | case DATABITS_8: 344 | lcr |= LCR_CS8; 345 | break; 346 | default: 347 | throw new IllegalArgumentException("Unknown dataBits value: " + dataBits); 348 | } 349 | 350 | switch (parity) { 351 | case PARITY_NONE: 352 | break; 353 | case PARITY_ODD: 354 | lcr |= LCR_ENABLE_PAR; 355 | break; 356 | case PARITY_EVEN: 357 | lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN; 358 | break; 359 | case PARITY_MARK: 360 | lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE; 361 | break; 362 | case PARITY_SPACE: 363 | lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN; 364 | break; 365 | default: 366 | throw new IllegalArgumentException("Unknown parity value: " + parity); 367 | } 368 | 369 | switch (stopBits) { 370 | case STOPBITS_1: 371 | break; 372 | case STOPBITS_1_5: 373 | throw new IllegalArgumentException("Unsupported stopBits value: 1.5"); 374 | case STOPBITS_2: 375 | lcr |= LCR_STOP_BITS_2; 376 | break; 377 | default: 378 | throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); 379 | } 380 | 381 | int ret = controlOut(0x9a, 0x2518, lcr); 382 | if (ret < 0) { 383 | throw new IOException("Error setting control byte"); 384 | } 385 | } 386 | 387 | @Override 388 | public boolean getCD() throws IOException { 389 | return false; 390 | } 391 | 392 | @Override 393 | public boolean getCTS() throws IOException { 394 | return false; 395 | } 396 | 397 | @Override 398 | public boolean getDSR() throws IOException { 399 | return false; 400 | } 401 | 402 | @Override 403 | public boolean getDTR() throws IOException { 404 | return dtr; 405 | } 406 | 407 | @Override 408 | public void setDTR(boolean value) throws IOException { 409 | dtr = value; 410 | writeHandshakeByte(); 411 | } 412 | 413 | @Override 414 | public boolean getRI() throws IOException { 415 | return false; 416 | } 417 | 418 | @Override 419 | public boolean getRTS() throws IOException { 420 | return rts; 421 | } 422 | 423 | @Override 424 | public void setRTS(boolean value) throws IOException { 425 | rts = value; 426 | writeHandshakeByte(); 427 | } 428 | 429 | @Override 430 | public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException { 431 | return true; 432 | } 433 | 434 | } 435 | 436 | public static Map getSupportedDevices() { 437 | final Map supportedDevices = new LinkedHashMap(); 438 | supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{ 439 | UsbId.QINHENG_HL340 440 | }); 441 | return supportedDevices; 442 | } 443 | 444 | } -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbConstants; 25 | import android.hardware.usb.UsbDevice; 26 | import android.hardware.usb.UsbDeviceConnection; 27 | import android.hardware.usb.UsbEndpoint; 28 | import android.hardware.usb.UsbInterface; 29 | import android.hardware.usb.UsbRequest; 30 | import android.util.Log; 31 | 32 | import java.io.IOException; 33 | import java.nio.ByteBuffer; 34 | import java.util.ArrayList; 35 | import java.util.LinkedHashMap; 36 | import java.util.List; 37 | import java.util.Map; 38 | 39 | public class Cp21xxSerialDriver implements UsbSerialDriver { 40 | 41 | private static final String TAG = Cp21xxSerialDriver.class.getSimpleName(); 42 | 43 | private final UsbDevice mDevice; 44 | private final List mPorts; 45 | 46 | public Cp21xxSerialDriver(UsbDevice device) { 47 | mDevice = device; 48 | mPorts = new ArrayList<>(); 49 | for( int port = 0; port < device.getInterfaceCount(); port++) { 50 | mPorts.add(new Cp21xxSerialPort(mDevice, port)); 51 | } 52 | } 53 | 54 | @Override 55 | public UsbDevice getDevice() { 56 | return mDevice; 57 | } 58 | 59 | @Override 60 | public List getPorts() { 61 | return mPorts; 62 | } 63 | 64 | public class Cp21xxSerialPort extends CommonUsbSerialPort { 65 | 66 | private static final int DEFAULT_BAUD_RATE = 9600; 67 | 68 | private static final int USB_WRITE_TIMEOUT_MILLIS = 5000; 69 | 70 | /* 71 | * Configuration Request Types 72 | */ 73 | private static final int REQTYPE_HOST_TO_DEVICE = 0x41; 74 | 75 | /* 76 | * Configuration Request Codes 77 | */ 78 | private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00; 79 | private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01; 80 | private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03; 81 | private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07; 82 | private static final int SILABSER_SET_BAUDRATE = 0x1E; 83 | private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12; 84 | 85 | private static final int FLUSH_READ_CODE = 0x0a; 86 | private static final int FLUSH_WRITE_CODE = 0x05; 87 | 88 | /* 89 | * SILABSER_IFC_ENABLE_REQUEST_CODE 90 | */ 91 | private static final int UART_ENABLE = 0x0001; 92 | private static final int UART_DISABLE = 0x0000; 93 | 94 | /* 95 | * SILABSER_SET_BAUDDIV_REQUEST_CODE 96 | */ 97 | private static final int BAUD_RATE_GEN_FREQ = 0x384000; 98 | 99 | /* 100 | * SILABSER_SET_MHS_REQUEST_CODE 101 | */ 102 | private static final int MCR_DTR = 0x0001; 103 | private static final int MCR_RTS = 0x0002; 104 | private static final int MCR_ALL = 0x0003; 105 | 106 | private static final int CONTROL_WRITE_DTR = 0x0100; 107 | private static final int CONTROL_WRITE_RTS = 0x0200; 108 | 109 | private UsbEndpoint mReadEndpoint; 110 | private UsbEndpoint mWriteEndpoint; 111 | private UsbRequest mUsbRequest; 112 | 113 | // second port of Cp2105 has limited baudRate, dataBits, stopBits, parity 114 | // unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored 115 | private boolean mIsRestrictedPort; 116 | 117 | public Cp21xxSerialPort(UsbDevice device, int portNumber) { 118 | super(device, portNumber); 119 | } 120 | 121 | @Override 122 | public UsbSerialDriver getDriver() { 123 | return Cp21xxSerialDriver.this; 124 | } 125 | 126 | private int setConfigSingle(int request, int value) { 127 | return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value, 128 | mPortNumber, null, 0, USB_WRITE_TIMEOUT_MILLIS); 129 | } 130 | 131 | @Override 132 | public void open(UsbDeviceConnection connection) throws IOException { 133 | if (mConnection != null) { 134 | throw new IOException("Already opened."); 135 | } 136 | 137 | mConnection = connection; 138 | boolean opened = false; 139 | mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1; 140 | try { 141 | if(mPortNumber >= mDevice.getInterfaceCount()) { 142 | throw new IOException("Unknown port number"); 143 | } 144 | UsbInterface dataIface = mDevice.getInterface(mPortNumber); 145 | if (!mConnection.claimInterface(dataIface, true)) { 146 | throw new IOException("Could not claim interface " + mPortNumber); 147 | } 148 | for (int i = 0; i < dataIface.getEndpointCount(); i++) { 149 | UsbEndpoint ep = dataIface.getEndpoint(i); 150 | if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { 151 | if (ep.getDirection() == UsbConstants.USB_DIR_IN) { 152 | mReadEndpoint = ep; 153 | } else { 154 | mWriteEndpoint = ep; 155 | } 156 | } 157 | } 158 | 159 | setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE); 160 | setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS); 161 | setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE); 162 | // setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY); 163 | opened = true; 164 | } finally { 165 | if (!opened) { 166 | try { 167 | close(); 168 | } catch (IOException e) { 169 | // Ignore IOExceptions during close() 170 | } 171 | } 172 | } 173 | } 174 | 175 | @Override 176 | public void close() throws IOException { 177 | if (mConnection == null) { 178 | throw new IOException("Already closed"); 179 | } 180 | synchronized (this) { 181 | if(mUsbRequest != null) { 182 | mUsbRequest.cancel(); 183 | } 184 | } 185 | try { 186 | setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE); 187 | } catch (Exception ignored) 188 | {} 189 | try { 190 | mConnection.close(); 191 | } finally { 192 | mConnection = null; 193 | } 194 | } 195 | 196 | @Override 197 | public int read(byte[] dest, int timeoutMillis) throws IOException { 198 | final UsbRequest request = new UsbRequest(); 199 | try { 200 | request.initialize(mConnection, mReadEndpoint); 201 | final ByteBuffer buf = ByteBuffer.wrap(dest); 202 | if (!request.queue(buf, dest.length)) { 203 | throw new IOException("Error queueing request."); 204 | } 205 | mUsbRequest = request; 206 | final UsbRequest response = mConnection.requestWait(); 207 | synchronized (this) { 208 | mUsbRequest = null; 209 | } 210 | if (response == null) { 211 | throw new IOException("Null response"); 212 | } 213 | 214 | final int nread = buf.position(); 215 | if (nread > 0) { 216 | //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); 217 | return nread; 218 | } else { 219 | return 0; 220 | } 221 | } finally { 222 | mUsbRequest = null; 223 | request.close(); 224 | } 225 | } 226 | 227 | @Override 228 | public int write(byte[] src, int timeoutMillis) throws IOException { 229 | int offset = 0; 230 | 231 | while (offset < src.length) { 232 | final int writeLength; 233 | final int amtWritten; 234 | 235 | synchronized (mWriteBufferLock) { 236 | final byte[] writeBuffer; 237 | 238 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 239 | if (offset == 0) { 240 | writeBuffer = src; 241 | } else { 242 | // bulkTransfer does not support offsets, make a copy. 243 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 244 | writeBuffer = mWriteBuffer; 245 | } 246 | 247 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, 248 | timeoutMillis); 249 | } 250 | if (amtWritten <= 0) { 251 | throw new IOException("Error writing " + writeLength 252 | + " bytes at offset " + offset + " length=" + src.length); 253 | } 254 | 255 | Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); 256 | offset += amtWritten; 257 | } 258 | return offset; 259 | } 260 | 261 | private void setBaudRate(int baudRate) throws IOException { 262 | byte[] data = new byte[] { 263 | (byte) ( baudRate & 0xff), 264 | (byte) ((baudRate >> 8 ) & 0xff), 265 | (byte) ((baudRate >> 16) & 0xff), 266 | (byte) ((baudRate >> 24) & 0xff) 267 | }; 268 | int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE, 269 | 0, mPortNumber, data, 4, USB_WRITE_TIMEOUT_MILLIS); 270 | if (ret < 0) { 271 | throw new IOException("Error setting baud rate."); 272 | } 273 | } 274 | 275 | @Override 276 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) 277 | throws IOException { 278 | setBaudRate(baudRate); 279 | 280 | int configDataBits = 0; 281 | switch (dataBits) { 282 | case DATABITS_5: 283 | if(mIsRestrictedPort) 284 | throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); 285 | configDataBits |= 0x0500; 286 | break; 287 | case DATABITS_6: 288 | if(mIsRestrictedPort) 289 | throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); 290 | configDataBits |= 0x0600; 291 | break; 292 | case DATABITS_7: 293 | if(mIsRestrictedPort) 294 | throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); 295 | configDataBits |= 0x0700; 296 | break; 297 | case DATABITS_8: 298 | configDataBits |= 0x0800; 299 | break; 300 | default: 301 | throw new IllegalArgumentException("Unknown dataBits value: " + dataBits); 302 | } 303 | 304 | switch (parity) { 305 | case PARITY_NONE: 306 | break; 307 | case PARITY_ODD: 308 | configDataBits |= 0x0010; 309 | break; 310 | case PARITY_EVEN: 311 | configDataBits |= 0x0020; 312 | break; 313 | case PARITY_MARK: 314 | if(mIsRestrictedPort) 315 | throw new IllegalArgumentException("Unsupported parity value: mark"); 316 | configDataBits |= 0x0030; 317 | break; 318 | case PARITY_SPACE: 319 | if(mIsRestrictedPort) 320 | throw new IllegalArgumentException("Unsupported parity value: space"); 321 | configDataBits |= 0x0040; 322 | break; 323 | default: 324 | throw new IllegalArgumentException("Unknown parity value: " + parity); 325 | } 326 | 327 | switch (stopBits) { 328 | case STOPBITS_1: 329 | break; 330 | case STOPBITS_1_5: 331 | throw new IllegalArgumentException("Unsupported stopBits value: 1.5"); 332 | case STOPBITS_2: 333 | if(mIsRestrictedPort) 334 | throw new IllegalArgumentException("Unsupported stopBits value: 2"); 335 | configDataBits |= 2; 336 | break; 337 | default: 338 | throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); 339 | } 340 | setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits); 341 | } 342 | 343 | @Override 344 | public boolean getCD() throws IOException { 345 | return false; 346 | } 347 | 348 | @Override 349 | public boolean getCTS() throws IOException { 350 | return false; 351 | } 352 | 353 | @Override 354 | public boolean getDSR() throws IOException { 355 | return false; 356 | } 357 | 358 | @Override 359 | public boolean getDTR() throws IOException { 360 | return true; 361 | } 362 | 363 | @Override 364 | public void setDTR(boolean value) throws IOException { 365 | } 366 | 367 | @Override 368 | public boolean getRI() throws IOException { 369 | return false; 370 | } 371 | 372 | @Override 373 | public boolean getRTS() throws IOException { 374 | return true; 375 | } 376 | 377 | @Override 378 | public void setRTS(boolean value) throws IOException { 379 | } 380 | 381 | @Override 382 | public boolean purgeHwBuffers(boolean purgeReadBuffers, 383 | boolean purgeWriteBuffers) throws IOException { 384 | int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0) 385 | | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0); 386 | 387 | if (value != 0) { 388 | setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value); 389 | } 390 | 391 | return true; 392 | } 393 | 394 | } 395 | 396 | public static Map getSupportedDevices() { 397 | final Map supportedDevices = new LinkedHashMap(); 398 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS), 399 | new int[] { 400 | UsbId.SILABS_CP2102, 401 | UsbId.SILABS_CP2105, 402 | UsbId.SILABS_CP2108, 403 | UsbId.SILABS_CP2110 404 | }); 405 | return supportedDevices; 406 | } 407 | 408 | } 409 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbConstants; 25 | import android.hardware.usb.UsbDevice; 26 | import android.hardware.usb.UsbDeviceConnection; 27 | import android.hardware.usb.UsbEndpoint; 28 | import android.hardware.usb.UsbInterface; 29 | import android.hardware.usb.UsbRequest; 30 | import android.util.Log; 31 | 32 | import java.io.IOException; 33 | import java.nio.ByteBuffer; 34 | import java.util.Collections; 35 | import java.util.LinkedHashMap; 36 | import java.util.List; 37 | import java.util.Map; 38 | 39 | /** 40 | * USB CDC/ACM serial driver implementation. 41 | * 42 | * @author mike wakerly (opensource@hoho.com) 43 | * @see Universal 45 | * Serial Bus Class Definitions for Communication Devices, v1.1 46 | */ 47 | public class CdcAcmSerialDriver implements UsbSerialDriver { 48 | 49 | private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); 50 | 51 | private final UsbDevice mDevice; 52 | private final UsbSerialPort mPort; 53 | 54 | public CdcAcmSerialDriver(UsbDevice device) { 55 | mDevice = device; 56 | mPort = new CdcAcmSerialPort(device, 0); 57 | } 58 | 59 | @Override 60 | public UsbDevice getDevice() { 61 | return mDevice; 62 | } 63 | 64 | @Override 65 | public List getPorts() { 66 | return Collections.singletonList(mPort); 67 | } 68 | 69 | class CdcAcmSerialPort extends CommonUsbSerialPort { 70 | 71 | private UsbInterface mControlInterface; 72 | private UsbInterface mDataInterface; 73 | 74 | private UsbEndpoint mControlEndpoint; 75 | private UsbEndpoint mReadEndpoint; 76 | private UsbEndpoint mWriteEndpoint; 77 | 78 | private int mControlIndex; 79 | 80 | private boolean mRts = false; 81 | private boolean mDtr = false; 82 | 83 | private static final int USB_RECIP_INTERFACE = 0x01; 84 | private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; 85 | 86 | private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2 87 | private static final int GET_LINE_CODING = 0x21; 88 | private static final int SET_CONTROL_LINE_STATE = 0x22; 89 | private static final int SEND_BREAK = 0x23; 90 | 91 | public CdcAcmSerialPort(UsbDevice device, int portNumber) { 92 | super(device, portNumber); 93 | } 94 | 95 | @Override 96 | public UsbSerialDriver getDriver() { 97 | return CdcAcmSerialDriver.this; 98 | } 99 | 100 | @Override 101 | public void open(UsbDeviceConnection connection) throws IOException { 102 | if (mConnection != null) { 103 | throw new IOException("Already open"); 104 | } 105 | 106 | mConnection = connection; 107 | boolean opened = false; 108 | try { 109 | 110 | if (1 == mDevice.getInterfaceCount()) { 111 | Log.d(TAG,"device might be castrated ACM device, trying single interface logic"); 112 | openSingleInterface(); 113 | } else { 114 | Log.d(TAG,"trying default interface logic"); 115 | openInterface(); 116 | } 117 | 118 | opened = true; 119 | } finally { 120 | if (!opened) { 121 | mConnection = null; 122 | // just to be on the save side 123 | mControlEndpoint = null; 124 | mReadEndpoint = null; 125 | mWriteEndpoint = null; 126 | } 127 | } 128 | } 129 | 130 | private void openSingleInterface() throws IOException { 131 | // the following code is inspired by the cdc-acm driver 132 | // in the linux kernel 133 | 134 | mControlIndex = 0; 135 | mControlInterface = mDevice.getInterface(0); 136 | Log.d(TAG, "Control iface=" + mControlInterface); 137 | 138 | mDataInterface = mDevice.getInterface(0); 139 | Log.d(TAG, "data iface=" + mDataInterface); 140 | 141 | if (!mConnection.claimInterface(mControlInterface, true)) { 142 | throw new IOException("Could not claim shared control/data interface."); 143 | } 144 | 145 | int endCount = mControlInterface.getEndpointCount(); 146 | 147 | if (endCount < 3) { 148 | Log.d(TAG,"not enough endpoints - need 3. count=" + mControlInterface.getEndpointCount()); 149 | throw new IOException("Insufficient number of endpoints(" + mControlInterface.getEndpointCount() + ")"); 150 | } 151 | 152 | // Analyse endpoints for their properties 153 | mControlEndpoint = null; 154 | mReadEndpoint = null; 155 | mWriteEndpoint = null; 156 | for (int i = 0; i < endCount; ++i) { 157 | UsbEndpoint ep = mControlInterface.getEndpoint(i); 158 | if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && 159 | (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)) { 160 | Log.d(TAG,"Found controlling endpoint"); 161 | mControlEndpoint = ep; 162 | } else if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && 163 | (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) { 164 | Log.d(TAG,"Found reading endpoint"); 165 | mReadEndpoint = ep; 166 | } else if ((ep.getDirection() == UsbConstants.USB_DIR_OUT) && 167 | (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) { 168 | Log.d(TAG,"Found writing endpoint"); 169 | mWriteEndpoint = ep; 170 | } 171 | 172 | 173 | if ((mControlEndpoint != null) && 174 | (mReadEndpoint != null) && 175 | (mWriteEndpoint != null)) { 176 | Log.d(TAG,"Found all required endpoints"); 177 | break; 178 | } 179 | } 180 | 181 | if ((mControlEndpoint == null) || 182 | (mReadEndpoint == null) || 183 | (mWriteEndpoint == null)) { 184 | Log.d(TAG,"Could not establish all endpoints"); 185 | throw new IOException("Could not establish all endpoints"); 186 | } 187 | } 188 | 189 | private void openInterface() throws IOException { 190 | Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); 191 | 192 | mControlInterface = null; 193 | mDataInterface = null; 194 | for (int i = 0; i < mDevice.getInterfaceCount(); i++) { 195 | UsbInterface usbInterface = mDevice.getInterface(i); 196 | if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM) { 197 | mControlIndex = i; 198 | mControlInterface = usbInterface; 199 | } 200 | if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { 201 | mDataInterface = usbInterface; 202 | } 203 | } 204 | 205 | if(mControlInterface == null) { 206 | throw new IOException("no control interface."); 207 | } 208 | Log.d(TAG, "Control iface=" + mControlInterface); 209 | 210 | if (!mConnection.claimInterface(mControlInterface, true)) { 211 | throw new IOException("Could not claim control interface."); 212 | } 213 | 214 | mControlEndpoint = mControlInterface.getEndpoint(0); 215 | if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { 216 | throw new IOException("invalid control endpoint"); 217 | } 218 | 219 | if(mDataInterface == null) { 220 | throw new IOException("no data interface."); 221 | } 222 | Log.d(TAG, "data iface=" + mDataInterface); 223 | 224 | if (!mConnection.claimInterface(mDataInterface, true)) { 225 | throw new IOException("Could not claim data interface."); 226 | } 227 | 228 | mReadEndpoint = null; 229 | mWriteEndpoint = null; 230 | for (int i = 0; i < mDataInterface.getEndpointCount(); i++) { 231 | UsbEndpoint ep = mDataInterface.getEndpoint(i); 232 | if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) 233 | mReadEndpoint = ep; 234 | if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) 235 | mWriteEndpoint = ep; 236 | } 237 | if (mReadEndpoint == null || mWriteEndpoint == null) { 238 | throw new IOException("Could not get read&write endpoints."); 239 | } 240 | } 241 | 242 | private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException { 243 | int len = mConnection.controlTransfer( 244 | USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); 245 | if(len < 0) { 246 | throw new IOException("controlTransfer failed."); 247 | } 248 | return len; 249 | } 250 | 251 | @Override 252 | public void close() throws IOException { 253 | if (mConnection == null) { 254 | throw new IOException("Already closed"); 255 | } 256 | mConnection.close(); 257 | mConnection = null; 258 | } 259 | 260 | @Override 261 | public int read(byte[] dest, int timeoutMillis) throws IOException { 262 | final UsbRequest request = new UsbRequest(); 263 | try { 264 | request.initialize(mConnection, mReadEndpoint); 265 | final ByteBuffer buf = ByteBuffer.wrap(dest); 266 | if (!request.queue(buf, dest.length)) { 267 | throw new IOException("Error queueing request."); 268 | } 269 | 270 | final UsbRequest response = mConnection.requestWait(); 271 | if (response == null) { 272 | throw new IOException("Null response"); 273 | } 274 | 275 | final int nread = buf.position(); 276 | if (nread > 0) { 277 | //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); 278 | return nread; 279 | } else { 280 | return 0; 281 | } 282 | } finally { 283 | request.close(); 284 | } 285 | } 286 | 287 | @Override 288 | public int write(byte[] src, int timeoutMillis) throws IOException { 289 | // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. 290 | int offset = 0; 291 | 292 | while (offset < src.length) { 293 | final int writeLength; 294 | final int amtWritten; 295 | 296 | synchronized (mWriteBufferLock) { 297 | final byte[] writeBuffer; 298 | 299 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 300 | if (offset == 0) { 301 | writeBuffer = src; 302 | } else { 303 | // bulkTransfer does not support offsets, make a copy. 304 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 305 | writeBuffer = mWriteBuffer; 306 | } 307 | 308 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, 309 | timeoutMillis); 310 | } 311 | if (amtWritten <= 0) { 312 | throw new IOException("Error writing " + writeLength 313 | + " bytes at offset " + offset + " length=" + src.length); 314 | } 315 | 316 | Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); 317 | offset += amtWritten; 318 | } 319 | return offset; 320 | } 321 | 322 | @Override 323 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { 324 | byte stopBitsByte; 325 | switch (stopBits) { 326 | case STOPBITS_1: stopBitsByte = 0; break; 327 | case STOPBITS_1_5: stopBitsByte = 1; break; 328 | case STOPBITS_2: stopBitsByte = 2; break; 329 | default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits); 330 | } 331 | 332 | byte parityBitesByte; 333 | switch (parity) { 334 | case PARITY_NONE: parityBitesByte = 0; break; 335 | case PARITY_ODD: parityBitesByte = 1; break; 336 | case PARITY_EVEN: parityBitesByte = 2; break; 337 | case PARITY_MARK: parityBitesByte = 3; break; 338 | case PARITY_SPACE: parityBitesByte = 4; break; 339 | default: throw new IllegalArgumentException("Bad value for parity: " + parity); 340 | } 341 | 342 | byte[] msg = { 343 | (byte) ( baudRate & 0xff), 344 | (byte) ((baudRate >> 8 ) & 0xff), 345 | (byte) ((baudRate >> 16) & 0xff), 346 | (byte) ((baudRate >> 24) & 0xff), 347 | stopBitsByte, 348 | parityBitesByte, 349 | (byte) dataBits}; 350 | sendAcmControlMessage(SET_LINE_CODING, 0, msg); 351 | } 352 | 353 | @Override 354 | public boolean getCD() throws IOException { 355 | return false; // TODO 356 | } 357 | 358 | @Override 359 | public boolean getCTS() throws IOException { 360 | return false; // TODO 361 | } 362 | 363 | @Override 364 | public boolean getDSR() throws IOException { 365 | return false; // TODO 366 | } 367 | 368 | @Override 369 | public boolean getDTR() throws IOException { 370 | return mDtr; 371 | } 372 | 373 | @Override 374 | public void setDTR(boolean value) throws IOException { 375 | mDtr = value; 376 | setDtrRts(); 377 | } 378 | 379 | @Override 380 | public boolean getRI() throws IOException { 381 | return false; // TODO 382 | } 383 | 384 | @Override 385 | public boolean getRTS() throws IOException { 386 | return mRts; 387 | } 388 | 389 | @Override 390 | public void setRTS(boolean value) throws IOException { 391 | mRts = value; 392 | setDtrRts(); 393 | } 394 | 395 | private void setDtrRts() throws IOException { 396 | int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0); 397 | sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null); 398 | } 399 | 400 | } 401 | 402 | public static Map getSupportedDevices() { 403 | final Map supportedDevices = new LinkedHashMap(); 404 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO), 405 | new int[] { 406 | UsbId.ARDUINO_UNO, 407 | UsbId.ARDUINO_UNO_R3, 408 | UsbId.ARDUINO_MEGA_2560, 409 | UsbId.ARDUINO_MEGA_2560_R3, 410 | UsbId.ARDUINO_SERIAL_ADAPTER, 411 | UsbId.ARDUINO_SERIAL_ADAPTER_R3, 412 | UsbId.ARDUINO_MEGA_ADK, 413 | UsbId.ARDUINO_MEGA_ADK_R3, 414 | UsbId.ARDUINO_LEONARDO, 415 | UsbId.ARDUINO_MICRO, 416 | }); 417 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH), 418 | new int[] { 419 | UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL, 420 | }); 421 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL), 422 | new int[] { 423 | UsbId.ATMEL_LUFA_CDC_DEMO_APP, 424 | }); 425 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS), 426 | new int[] { 427 | UsbId.LEAFLABS_MAPLE, 428 | }); 429 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARM), 430 | new int[] { 431 | UsbId.ARM_MBED, 432 | }); 433 | return supportedDevices; 434 | } 435 | 436 | } 437 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbConstants; 25 | import android.hardware.usb.UsbDevice; 26 | import android.hardware.usb.UsbDeviceConnection; 27 | import android.hardware.usb.UsbEndpoint; 28 | import android.hardware.usb.UsbRequest; 29 | import android.util.Log; 30 | 31 | import java.io.IOException; 32 | import java.nio.ByteBuffer; 33 | import java.util.ArrayList; 34 | import java.util.LinkedHashMap; 35 | import java.util.List; 36 | import java.util.Map; 37 | 38 | /** 39 | * A {@link CommonUsbSerialPort} implementation for a variety of FTDI devices 40 | *

41 | * This driver is based on libftdi, and is 43 | * copyright and subject to the following terms: 44 | * 45 | *

 46 |  *   Copyright (C) 2003 by Intra2net AG
 47 |  *
 48 |  *   This program is free software; you can redistribute it and/or modify
 49 |  *   it under the terms of the GNU Lesser General Public License
 50 |  *   version 2.1 as published by the Free Software Foundation;
 51 |  *
 52 |  *   opensource@intra2net.com
 53 |  *   http://www.intra2net.com/en/developer/libftdi
 54 |  * 
55 | * 56 | *

57 | *

58 | * Some FTDI devices have not been tested; see later listing of supported and 59 | * unsupported devices. Devices listed as "supported" support the following 60 | * features: 61 | *

    62 | *
  • Read and write of serial data (see 63 | * {@link CommonUsbSerialPort#read(byte[], int)} and 64 | * {@link CommonUsbSerialPort#write(byte[], int)}.
  • 65 | *
  • Setting serial line parameters (see 66 | * {@link CommonUsbSerialPort#setParameters(int, int, int, int)}.
  • 67 | *
68 | *

69 | *

70 | * Supported and tested devices: 71 | *

    72 | *
  • {@value DeviceType#TYPE_R}
  • 73 | *
  • {@value DeviceType#TYPE_2232H}
  • 74 | *
  • {@value DeviceType#TYPE_4232H}
  • 75 | *
76 | *

77 | *

78 | * Unsupported but possibly working devices (please contact the author with 79 | * feedback or patches): 80 | *

    81 | *
  • {@value DeviceType#TYPE_2232C}
  • 82 | *
  • {@value DeviceType#TYPE_AM}
  • 83 | *
  • {@value DeviceType#TYPE_BM}
  • 84 | *
85 | *

86 | * 87 | * @author mike wakerly (opensource@hoho.com) 88 | * @see USB Serial 89 | * for Android project page 90 | * @see FTDI Homepage 91 | * @see libftdi 92 | */ 93 | public class FtdiSerialDriver implements UsbSerialDriver { 94 | 95 | private final UsbDevice mDevice; 96 | private final List mPorts; 97 | 98 | /** 99 | * FTDI chip types. 100 | */ 101 | private static enum DeviceType { 102 | TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H; 103 | } 104 | 105 | public FtdiSerialDriver(UsbDevice device) { 106 | mDevice = device; 107 | mPorts = new ArrayList<>(); 108 | for( int port = 0; port < device.getInterfaceCount(); port++) { 109 | mPorts.add(new FtdiSerialPort(mDevice, port)); 110 | } 111 | } 112 | 113 | @Override 114 | public UsbDevice getDevice() { 115 | return mDevice; 116 | } 117 | 118 | @Override 119 | public List getPorts() { 120 | return mPorts; 121 | } 122 | 123 | private class FtdiSerialPort extends CommonUsbSerialPort { 124 | 125 | public static final int USB_TYPE_STANDARD = 0x00 << 5; 126 | public static final int USB_TYPE_CLASS = 0x00 << 5; 127 | public static final int USB_TYPE_VENDOR = 0x00 << 5; 128 | public static final int USB_TYPE_RESERVED = 0x00 << 5; 129 | 130 | public static final int USB_RECIP_DEVICE = 0x00; 131 | public static final int USB_RECIP_INTERFACE = 0x01; 132 | public static final int USB_RECIP_ENDPOINT = 0x02; 133 | public static final int USB_RECIP_OTHER = 0x03; 134 | 135 | public static final int USB_ENDPOINT_IN = 0x80; 136 | public static final int USB_ENDPOINT_OUT = 0x00; 137 | 138 | public static final int USB_WRITE_TIMEOUT_MILLIS = 5000; 139 | public static final int USB_READ_TIMEOUT_MILLIS = 5000; 140 | 141 | // From ftdi.h 142 | /** 143 | * Reset the port. 144 | */ 145 | private static final int SIO_RESET_REQUEST = 0; 146 | 147 | /** 148 | * Set the modem control register. 149 | */ 150 | private static final int SIO_MODEM_CTRL_REQUEST = 1; 151 | 152 | /** 153 | * Set flow control register. 154 | */ 155 | private static final int SIO_SET_FLOW_CTRL_REQUEST = 2; 156 | 157 | /** 158 | * Set baud rate. 159 | */ 160 | private static final int SIO_SET_BAUD_RATE_REQUEST = 3; 161 | 162 | /** 163 | * Set the data characteristics of the port. 164 | */ 165 | private static final int SIO_SET_DATA_REQUEST = 4; 166 | 167 | private static final int SIO_RESET_SIO = 0; 168 | private static final int SIO_RESET_PURGE_RX = 1; 169 | private static final int SIO_RESET_PURGE_TX = 2; 170 | 171 | public static final int FTDI_DEVICE_OUT_REQTYPE = 172 | UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT; 173 | 174 | public static final int FTDI_DEVICE_IN_REQTYPE = 175 | UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN; 176 | 177 | /** 178 | * Length of the modem status header, transmitted with every read. 179 | */ 180 | private static final int MODEM_STATUS_HEADER_LENGTH = 2; 181 | 182 | private final String TAG = FtdiSerialDriver.class.getSimpleName(); 183 | 184 | private DeviceType mType; 185 | 186 | private int mIndex = 0; 187 | 188 | public FtdiSerialPort(UsbDevice device, int portNumber) { 189 | super(device, portNumber); 190 | } 191 | 192 | @Override 193 | public UsbSerialDriver getDriver() { 194 | return FtdiSerialDriver.this; 195 | } 196 | 197 | /** 198 | * Filter FTDI status bytes from buffer 199 | * @param src The source buffer (which contains status bytes) 200 | * @param dest The destination buffer to write the status bytes into (can be src) 201 | * @param totalBytesRead Number of bytes read to src 202 | * @param maxPacketSize The USB endpoint max packet size 203 | * @return The number of payload bytes 204 | */ 205 | private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) { 206 | final int packetsCount = (totalBytesRead + maxPacketSize -1 )/ maxPacketSize; 207 | for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) { 208 | final int count = (packetIdx == (packetsCount - 1)) 209 | ? totalBytesRead - packetIdx * maxPacketSize - MODEM_STATUS_HEADER_LENGTH 210 | : maxPacketSize - MODEM_STATUS_HEADER_LENGTH; 211 | if (count > 0) { 212 | System.arraycopy(src, 213 | packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH, 214 | dest, 215 | packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH), 216 | count); 217 | } 218 | } 219 | 220 | return totalBytesRead - (packetsCount * 2); 221 | } 222 | 223 | public void reset() throws IOException { 224 | // TODO(mikey): autodetect. 225 | mType = DeviceType.TYPE_R; 226 | if(mDevice.getInterfaceCount() > 1) { 227 | mIndex = mPortNumber + 1; 228 | if (mDevice.getInterfaceCount() == 2) 229 | mType = DeviceType.TYPE_2232H; 230 | if (mDevice.getInterfaceCount() == 4) 231 | mType = DeviceType.TYPE_4232H; 232 | } 233 | 234 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, 235 | SIO_RESET_SIO, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); 236 | if (result != 0) { 237 | throw new IOException("Reset failed: result=" + result); 238 | } 239 | } 240 | 241 | @Override 242 | public void open(UsbDeviceConnection connection) throws IOException { 243 | if (mConnection != null) { 244 | throw new IOException("Already open"); 245 | } 246 | mConnection = connection; 247 | 248 | boolean opened = false; 249 | try { 250 | if (connection.claimInterface(mDevice.getInterface(mPortNumber), true)) { 251 | Log.d(TAG, "claimInterface " + mPortNumber + " SUCCESS"); 252 | } else { 253 | throw new IOException("Error claiming interface " + mPortNumber); 254 | } 255 | reset(); 256 | opened = true; 257 | } finally { 258 | if (!opened) { 259 | close(); 260 | mConnection = null; 261 | } 262 | } 263 | } 264 | 265 | @Override 266 | public void close() throws IOException { 267 | if (mConnection == null) { 268 | throw new IOException("Already closed"); 269 | } 270 | try { 271 | mConnection.close(); 272 | } finally { 273 | mConnection = null; 274 | } 275 | } 276 | 277 | @Override 278 | public int read(byte[] dest, int timeoutMillis) throws IOException { 279 | final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(0); 280 | final UsbRequest request = new UsbRequest(); 281 | final ByteBuffer buf = ByteBuffer.wrap(dest); 282 | try { 283 | request.initialize(mConnection, endpoint); 284 | if (!request.queue(buf, dest.length)) { 285 | throw new IOException("Error queueing request."); 286 | } 287 | 288 | final UsbRequest response = mConnection.requestWait(); 289 | if (response == null) { 290 | throw new IOException("Null response"); 291 | } 292 | } finally { 293 | request.close(); 294 | } 295 | 296 | final int totalBytesRead = buf.position(); 297 | if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) { 298 | throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes"); 299 | } 300 | 301 | return filterStatusBytes(dest, dest, totalBytesRead, endpoint.getMaxPacketSize()); 302 | } 303 | 304 | @Override 305 | public int write(byte[] src, int timeoutMillis) throws IOException { 306 | final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(1); 307 | int offset = 0; 308 | 309 | while (offset < src.length) { 310 | final int writeLength; 311 | final int amtWritten; 312 | 313 | synchronized (mWriteBufferLock) { 314 | final byte[] writeBuffer; 315 | 316 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 317 | if (offset == 0) { 318 | writeBuffer = src; 319 | } else { 320 | // bulkTransfer does not support offsets, make a copy. 321 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 322 | writeBuffer = mWriteBuffer; 323 | } 324 | 325 | amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength, 326 | timeoutMillis); 327 | } 328 | 329 | if (amtWritten <= 0) { 330 | throw new IOException("Error writing " + writeLength 331 | + " bytes at offset " + offset + " length=" + src.length); 332 | } 333 | 334 | Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength); 335 | offset += amtWritten; 336 | } 337 | return offset; 338 | } 339 | 340 | private int setBaudRate(int baudRate) throws IOException { 341 | long[] vals = convertBaudrate(baudRate); 342 | long actualBaudrate = vals[0]; 343 | long index = vals[1]; 344 | long value = vals[2]; 345 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, 346 | SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index, 347 | null, 0, USB_WRITE_TIMEOUT_MILLIS); 348 | if (result != 0) { 349 | throw new IOException("Setting baudrate failed: result=" + result); 350 | } 351 | return (int) actualBaudrate; 352 | } 353 | 354 | @Override 355 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) 356 | throws IOException { 357 | setBaudRate(baudRate); 358 | 359 | int config = 0; 360 | switch (dataBits) { 361 | case DATABITS_5: 362 | case DATABITS_6: 363 | throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); 364 | case DATABITS_7: 365 | case DATABITS_8: 366 | config |= dataBits; 367 | break; 368 | default: 369 | throw new IllegalArgumentException("Unknown dataBits value: " + dataBits); 370 | } 371 | 372 | switch (parity) { 373 | case PARITY_NONE: 374 | config |= (0x00 << 8); 375 | break; 376 | case PARITY_ODD: 377 | config |= (0x01 << 8); 378 | break; 379 | case PARITY_EVEN: 380 | config |= (0x02 << 8); 381 | break; 382 | case PARITY_MARK: 383 | config |= (0x03 << 8); 384 | break; 385 | case PARITY_SPACE: 386 | config |= (0x04 << 8); 387 | break; 388 | default: 389 | throw new IllegalArgumentException("Unknown parity value: " + parity); 390 | } 391 | 392 | switch (stopBits) { 393 | case STOPBITS_1: 394 | config |= (0x00 << 11); 395 | break; 396 | case STOPBITS_1_5: 397 | throw new IllegalArgumentException("Unsupported stopBits value: 1.5"); 398 | case STOPBITS_2: 399 | config |= (0x02 << 11); 400 | break; 401 | default: 402 | throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); 403 | } 404 | 405 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, 406 | SIO_SET_DATA_REQUEST, config, mIndex, 407 | null, 0, USB_WRITE_TIMEOUT_MILLIS); 408 | if (result != 0) { 409 | throw new IOException("Setting parameters failed: result=" + result); 410 | } 411 | } 412 | 413 | private long[] convertBaudrate(int baudrate) { 414 | // TODO(mikey): Braindead transcription of libfti method. Clean up, 415 | // using more idiomatic Java where possible. 416 | int divisor = 24000000 / baudrate; 417 | int bestDivisor = 0; 418 | int bestBaud = 0; 419 | int bestBaudDiff = 0; 420 | int fracCode[] = { 421 | 0, 3, 2, 4, 1, 5, 6, 7 422 | }; 423 | 424 | for (int i = 0; i < 2; i++) { 425 | int tryDivisor = divisor + i; 426 | int baudEstimate; 427 | int baudDiff; 428 | 429 | if (tryDivisor <= 8) { 430 | // Round up to minimum supported divisor 431 | tryDivisor = 8; 432 | } else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) { 433 | // BM doesn't support divisors 9 through 11 inclusive 434 | tryDivisor = 12; 435 | } else if (divisor < 16) { 436 | // AM doesn't support divisors 9 through 15 inclusive 437 | tryDivisor = 16; 438 | } else { 439 | if (mType == DeviceType.TYPE_AM) { 440 | // TODO 441 | } else { 442 | if (tryDivisor > 0x1FFFF) { 443 | // Round down to maximum supported divisor value (for 444 | // BM) 445 | tryDivisor = 0x1FFFF; 446 | } 447 | } 448 | } 449 | 450 | // Get estimated baud rate (to nearest integer) 451 | baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor; 452 | 453 | // Get absolute difference from requested baud rate 454 | if (baudEstimate < baudrate) { 455 | baudDiff = baudrate - baudEstimate; 456 | } else { 457 | baudDiff = baudEstimate - baudrate; 458 | } 459 | 460 | if (i == 0 || baudDiff < bestBaudDiff) { 461 | // Closest to requested baud rate so far 462 | bestDivisor = tryDivisor; 463 | bestBaud = baudEstimate; 464 | bestBaudDiff = baudDiff; 465 | if (baudDiff == 0) { 466 | // Spot on! No point trying 467 | break; 468 | } 469 | } 470 | } 471 | 472 | // Encode the best divisor value 473 | long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14); 474 | // Deal with special cases for encoded value 475 | if (encodedDivisor == 1) { 476 | encodedDivisor = 0; // 3000000 baud 477 | } else if (encodedDivisor == 0x4001) { 478 | encodedDivisor = 1; // 2000000 baud (BM only) 479 | } 480 | 481 | // Split into "value" and "index" values 482 | long value = encodedDivisor & 0xFFFF; 483 | long index; 484 | if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H 485 | || mType == DeviceType.TYPE_4232H) { 486 | index = (encodedDivisor >> 8) & 0xff00; 487 | index |= mIndex; 488 | } else { 489 | index = (encodedDivisor >> 16) & 0xffff; 490 | } 491 | 492 | // Return the nearest baud rate 493 | return new long[] { 494 | bestBaud, index, value 495 | }; 496 | } 497 | 498 | @Override 499 | public boolean getCD() throws IOException { 500 | return false; 501 | } 502 | 503 | @Override 504 | public boolean getCTS() throws IOException { 505 | return false; 506 | } 507 | 508 | @Override 509 | public boolean getDSR() throws IOException { 510 | return false; 511 | } 512 | 513 | @Override 514 | public boolean getDTR() throws IOException { 515 | return false; 516 | } 517 | 518 | @Override 519 | public void setDTR(boolean value) throws IOException { 520 | } 521 | 522 | @Override 523 | public boolean getRI() throws IOException { 524 | return false; 525 | } 526 | 527 | @Override 528 | public boolean getRTS() throws IOException { 529 | return false; 530 | } 531 | 532 | @Override 533 | public void setRTS(boolean value) throws IOException { 534 | } 535 | 536 | @Override 537 | public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException { 538 | if (purgeReadBuffers) { 539 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, 540 | SIO_RESET_PURGE_RX, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); 541 | if (result != 0) { 542 | throw new IOException("Flushing RX failed: result=" + result); 543 | } 544 | } 545 | 546 | if (purgeWriteBuffers) { 547 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, 548 | SIO_RESET_PURGE_TX, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); 549 | if (result != 0) { 550 | throw new IOException("Flushing RX failed: result=" + result); 551 | } 552 | } 553 | return true; 554 | } 555 | } 556 | 557 | public static Map getSupportedDevices() { 558 | final Map supportedDevices = new LinkedHashMap(); 559 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI), 560 | new int[] { 561 | UsbId.FTDI_FT232R, 562 | UsbId.FTDI_FT232H, 563 | UsbId.FTDI_FT2232H, 564 | UsbId.FTDI_FT4232H, 565 | UsbId.FTDI_FT231X, 566 | }); 567 | return supportedDevices; 568 | } 569 | 570 | } 571 | -------------------------------------------------------------------------------- /usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* This library is free software; you can redistribute it and/or 2 | * modify it under the terms of the GNU Lesser General Public 3 | * License as published by the Free Software Foundation; either 4 | * version 2.1 of the License, or (at your option) any later version. 5 | * 6 | * This library is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | * Lesser General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU Lesser General Public 12 | * License along with this library; if not, write to the Free Software 13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 14 | * USA. 15 | * 16 | * Project home page: https://github.com/mik3y/usb-serial-for-android 17 | */ 18 | 19 | /* 20 | * Ported to usb-serial-for-android 21 | * by Felix Hädicke 22 | * 23 | * Based on the pyprolific driver written 24 | * by Emmanuel Blot 25 | * See https://github.com/eblot/pyftdi 26 | */ 27 | 28 | package com.hoho.android.usbserial.driver; 29 | 30 | import android.hardware.usb.UsbConstants; 31 | import android.hardware.usb.UsbDevice; 32 | import android.hardware.usb.UsbDeviceConnection; 33 | import android.hardware.usb.UsbEndpoint; 34 | import android.hardware.usb.UsbInterface; 35 | import android.hardware.usb.UsbRequest; 36 | import android.util.Log; 37 | 38 | import java.io.IOException; 39 | import java.lang.reflect.Method; 40 | import java.nio.ByteBuffer; 41 | import java.util.Collections; 42 | import java.util.LinkedHashMap; 43 | import java.util.List; 44 | import java.util.Map; 45 | 46 | public class ProlificSerialDriver implements UsbSerialDriver { 47 | 48 | private final String TAG = ProlificSerialDriver.class.getSimpleName(); 49 | 50 | private final UsbDevice mDevice; 51 | private final UsbSerialPort mPort; 52 | 53 | public ProlificSerialDriver(UsbDevice device) { 54 | mDevice = device; 55 | mPort = new ProlificSerialPort(mDevice, 0); 56 | } 57 | 58 | @Override 59 | public List getPorts() { 60 | return Collections.singletonList(mPort); 61 | } 62 | 63 | @Override 64 | public UsbDevice getDevice() { 65 | return mDevice; 66 | } 67 | 68 | class ProlificSerialPort extends CommonUsbSerialPort { 69 | 70 | private static final int USB_READ_TIMEOUT_MILLIS = 1000; 71 | private static final int USB_WRITE_TIMEOUT_MILLIS = 5000; 72 | 73 | private static final int USB_RECIP_INTERFACE = 0x01; 74 | 75 | private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01; 76 | private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01; 77 | 78 | private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT 79 | | UsbConstants.USB_TYPE_VENDOR; 80 | 81 | private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN 82 | | UsbConstants.USB_TYPE_VENDOR; 83 | 84 | private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT 85 | | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; 86 | 87 | private static final int WRITE_ENDPOINT = 0x02; 88 | private static final int READ_ENDPOINT = 0x83; 89 | private static final int INTERRUPT_ENDPOINT = 0x81; 90 | 91 | private static final int FLUSH_RX_REQUEST = 0x08; 92 | private static final int FLUSH_TX_REQUEST = 0x09; 93 | 94 | private static final int SET_LINE_REQUEST = 0x20; 95 | private static final int SET_CONTROL_REQUEST = 0x22; 96 | 97 | private static final int CONTROL_DTR = 0x01; 98 | private static final int CONTROL_RTS = 0x02; 99 | 100 | private static final int STATUS_FLAG_CD = 0x01; 101 | private static final int STATUS_FLAG_DSR = 0x02; 102 | private static final int STATUS_FLAG_RI = 0x08; 103 | private static final int STATUS_FLAG_CTS = 0x80; 104 | 105 | private static final int STATUS_BUFFER_SIZE = 10; 106 | private static final int STATUS_BYTE_IDX = 8; 107 | 108 | private static final int DEVICE_TYPE_HX = 0; 109 | private static final int DEVICE_TYPE_0 = 1; 110 | private static final int DEVICE_TYPE_1 = 2; 111 | 112 | private int mDeviceType = DEVICE_TYPE_HX; 113 | 114 | private UsbEndpoint mReadEndpoint; 115 | private UsbEndpoint mWriteEndpoint; 116 | private UsbEndpoint mInterruptEndpoint; 117 | 118 | private int mControlLinesValue = 0; 119 | 120 | private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1; 121 | 122 | private int mStatus = 0; 123 | private volatile Thread mReadStatusThread = null; 124 | private final Object mReadStatusThreadLock = new Object(); 125 | boolean mStopReadStatusThread = false; 126 | private IOException mReadStatusException = null; 127 | 128 | 129 | public ProlificSerialPort(UsbDevice device, int portNumber) { 130 | super(device, portNumber); 131 | } 132 | 133 | @Override 134 | public UsbSerialDriver getDriver() { 135 | return ProlificSerialDriver.this; 136 | } 137 | 138 | private final byte[] inControlTransfer(int requestType, int request, 139 | int value, int index, int length) throws IOException { 140 | byte[] buffer = new byte[length]; 141 | int result = mConnection.controlTransfer(requestType, request, value, 142 | index, buffer, length, USB_READ_TIMEOUT_MILLIS); 143 | if (result != length) { 144 | throw new IOException( 145 | String.format("ControlTransfer with value 0x%x failed: %d", 146 | value, result)); 147 | } 148 | return buffer; 149 | } 150 | 151 | private final void outControlTransfer(int requestType, int request, 152 | int value, int index, byte[] data) throws IOException { 153 | int length = (data == null) ? 0 : data.length; 154 | int result = mConnection.controlTransfer(requestType, request, value, 155 | index, data, length, USB_WRITE_TIMEOUT_MILLIS); 156 | if (result != length) { 157 | throw new IOException( 158 | String.format("ControlTransfer with value 0x%x failed: %d", 159 | value, result)); 160 | } 161 | } 162 | 163 | private final byte[] vendorIn(int value, int index, int length) 164 | throws IOException { 165 | return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE, 166 | PROLIFIC_VENDOR_READ_REQUEST, value, index, length); 167 | } 168 | 169 | private final void vendorOut(int value, int index, byte[] data) 170 | throws IOException { 171 | outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE, 172 | PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data); 173 | } 174 | 175 | private void resetDevice() throws IOException { 176 | purgeHwBuffers(true, true); 177 | } 178 | 179 | private final void ctrlOut(int request, int value, int index, byte[] data) 180 | throws IOException { 181 | outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index, 182 | data); 183 | } 184 | 185 | private void doBlackMagic() throws IOException { 186 | vendorIn(0x8484, 0, 1); 187 | vendorOut(0x0404, 0, null); 188 | vendorIn(0x8484, 0, 1); 189 | vendorIn(0x8383, 0, 1); 190 | vendorIn(0x8484, 0, 1); 191 | vendorOut(0x0404, 1, null); 192 | vendorIn(0x8484, 0, 1); 193 | vendorIn(0x8383, 0, 1); 194 | vendorOut(0, 1, null); 195 | vendorOut(1, 0, null); 196 | vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null); 197 | } 198 | 199 | private void setControlLines(int newControlLinesValue) throws IOException { 200 | ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null); 201 | mControlLinesValue = newControlLinesValue; 202 | } 203 | 204 | private final void readStatusThreadFunction() { 205 | try { 206 | while (!mStopReadStatusThread) { 207 | byte[] buffer = new byte[STATUS_BUFFER_SIZE]; 208 | int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, 209 | buffer, 210 | STATUS_BUFFER_SIZE, 211 | 500); 212 | if (readBytesCount > 0) { 213 | if (readBytesCount == STATUS_BUFFER_SIZE) { 214 | mStatus = buffer[STATUS_BYTE_IDX] & 0xff; 215 | } else { 216 | throw new IOException( 217 | String.format("Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d", 218 | STATUS_BUFFER_SIZE, 219 | readBytesCount)); 220 | } 221 | } 222 | } 223 | } catch (IOException e) { 224 | mReadStatusException = e; 225 | } 226 | } 227 | 228 | private final int getStatus() throws IOException { 229 | if ((mReadStatusThread == null) && (mReadStatusException == null)) { 230 | synchronized (mReadStatusThreadLock) { 231 | if (mReadStatusThread == null) { 232 | byte[] buffer = new byte[STATUS_BUFFER_SIZE]; 233 | int readBytes = mConnection.bulkTransfer(mInterruptEndpoint, 234 | buffer, 235 | STATUS_BUFFER_SIZE, 236 | 100); 237 | if (readBytes != STATUS_BUFFER_SIZE) { 238 | Log.w(TAG, "Could not read initial CTS / DSR / CD / RI status"); 239 | } else { 240 | mStatus = buffer[STATUS_BYTE_IDX] & 0xff; 241 | } 242 | 243 | mReadStatusThread = new Thread(new Runnable() { 244 | @Override 245 | public void run() { 246 | readStatusThreadFunction(); 247 | } 248 | }); 249 | mReadStatusThread.setDaemon(true); 250 | mReadStatusThread.start(); 251 | } 252 | } 253 | } 254 | 255 | /* throw and clear an exception which occured in the status read thread */ 256 | IOException readStatusException = mReadStatusException; 257 | if (mReadStatusException != null) { 258 | mReadStatusException = null; 259 | throw readStatusException; 260 | } 261 | 262 | return mStatus; 263 | } 264 | 265 | private final boolean testStatusFlag(int flag) throws IOException { 266 | return ((getStatus() & flag) == flag); 267 | } 268 | 269 | @Override 270 | public void open(UsbDeviceConnection connection) throws IOException { 271 | if (mConnection != null) { 272 | throw new IOException("Already open"); 273 | } 274 | 275 | UsbInterface usbInterface = mDevice.getInterface(0); 276 | 277 | if (!connection.claimInterface(usbInterface, true)) { 278 | throw new IOException("Error claiming Prolific interface 0"); 279 | } 280 | 281 | mConnection = connection; 282 | boolean opened = false; 283 | try { 284 | for (int i = 0; i < usbInterface.getEndpointCount(); ++i) { 285 | UsbEndpoint currentEndpoint = usbInterface.getEndpoint(i); 286 | 287 | switch (currentEndpoint.getAddress()) { 288 | case READ_ENDPOINT: 289 | mReadEndpoint = currentEndpoint; 290 | break; 291 | 292 | case WRITE_ENDPOINT: 293 | mWriteEndpoint = currentEndpoint; 294 | break; 295 | 296 | case INTERRUPT_ENDPOINT: 297 | mInterruptEndpoint = currentEndpoint; 298 | break; 299 | } 300 | } 301 | 302 | if (mDevice.getDeviceClass() == 0x02) { 303 | mDeviceType = DEVICE_TYPE_0; 304 | } else { 305 | try { 306 | Method getRawDescriptorsMethod 307 | = mConnection.getClass().getMethod("getRawDescriptors"); 308 | byte[] rawDescriptors 309 | = (byte[]) getRawDescriptorsMethod.invoke(mConnection); 310 | byte maxPacketSize0 = rawDescriptors[7]; 311 | if (maxPacketSize0 == 64) { 312 | mDeviceType = DEVICE_TYPE_HX; 313 | } else if ((mDevice.getDeviceClass() == 0x00) 314 | || (mDevice.getDeviceClass() == 0xff)) { 315 | mDeviceType = DEVICE_TYPE_1; 316 | } else { 317 | Log.w(TAG, "Could not detect PL2303 subtype, " 318 | + "Assuming that it is a HX device"); 319 | mDeviceType = DEVICE_TYPE_HX; 320 | } 321 | } catch (NoSuchMethodException e) { 322 | Log.w(TAG, "Method UsbDeviceConnection.getRawDescriptors, " 323 | + "required for PL2303 subtype detection, not " 324 | + "available! Assuming that it is a HX device"); 325 | mDeviceType = DEVICE_TYPE_HX; 326 | } catch (Exception e) { 327 | Log.e(TAG, "An unexpected exception occured while trying " 328 | + "to detect PL2303 subtype", e); 329 | } 330 | } 331 | 332 | setControlLines(mControlLinesValue); 333 | resetDevice(); 334 | 335 | doBlackMagic(); 336 | opened = true; 337 | } finally { 338 | if (!opened) { 339 | mConnection = null; 340 | connection.releaseInterface(usbInterface); 341 | } 342 | } 343 | } 344 | 345 | @Override 346 | public void close() throws IOException { 347 | if (mConnection == null) { 348 | throw new IOException("Already closed"); 349 | } 350 | try { 351 | mStopReadStatusThread = true; 352 | synchronized (mReadStatusThreadLock) { 353 | if (mReadStatusThread != null) { 354 | try { 355 | mReadStatusThread.join(); 356 | } catch (Exception e) { 357 | Log.w(TAG, "An error occured while waiting for status read thread", e); 358 | } 359 | } 360 | } 361 | resetDevice(); 362 | } finally { 363 | try { 364 | mConnection.releaseInterface(mDevice.getInterface(0)); 365 | } finally { 366 | mConnection = null; 367 | } 368 | } 369 | } 370 | 371 | @Override 372 | public int read(byte[] dest, int timeoutMillis) throws IOException { 373 | final UsbRequest request = new UsbRequest(); 374 | try { 375 | request.initialize(mConnection, mReadEndpoint); 376 | final ByteBuffer buf = ByteBuffer.wrap(dest); 377 | if (!request.queue(buf, dest.length)) { 378 | throw new IOException("Error queueing request."); 379 | } 380 | 381 | final UsbRequest response = mConnection.requestWait(); 382 | if (response == null) { 383 | throw new IOException("Null response"); 384 | } 385 | 386 | final int nread = buf.position(); 387 | if (nread > 0) { 388 | //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); 389 | return nread; 390 | } else { 391 | return 0; 392 | } 393 | } finally { 394 | request.close(); 395 | } 396 | } 397 | 398 | @Override 399 | public int write(byte[] src, int timeoutMillis) throws IOException { 400 | int offset = 0; 401 | 402 | while (offset < src.length) { 403 | final int writeLength; 404 | final int amtWritten; 405 | 406 | synchronized (mWriteBufferLock) { 407 | final byte[] writeBuffer; 408 | 409 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 410 | if (offset == 0) { 411 | writeBuffer = src; 412 | } else { 413 | // bulkTransfer does not support offsets, make a copy. 414 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 415 | writeBuffer = mWriteBuffer; 416 | } 417 | 418 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, 419 | writeBuffer, writeLength, timeoutMillis); 420 | } 421 | 422 | if (amtWritten <= 0) { 423 | throw new IOException("Error writing " + writeLength 424 | + " bytes at offset " + offset + " length=" 425 | + src.length); 426 | } 427 | 428 | offset += amtWritten; 429 | } 430 | return offset; 431 | } 432 | 433 | @Override 434 | public void setParameters(int baudRate, int dataBits, int stopBits, 435 | int parity) throws IOException { 436 | if ((mBaudRate == baudRate) && (mDataBits == dataBits) 437 | && (mStopBits == stopBits) && (mParity == parity)) { 438 | // Make sure no action is performed if there is nothing to change 439 | return; 440 | } 441 | 442 | byte[] lineRequestData = new byte[7]; 443 | 444 | lineRequestData[0] = (byte) (baudRate & 0xff); 445 | lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff); 446 | lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff); 447 | lineRequestData[3] = (byte) ((baudRate >> 24) & 0xff); 448 | 449 | switch (stopBits) { 450 | case STOPBITS_1: 451 | lineRequestData[4] = 0; 452 | break; 453 | 454 | case STOPBITS_1_5: 455 | lineRequestData[4] = 1; 456 | break; 457 | 458 | case STOPBITS_2: 459 | lineRequestData[4] = 2; 460 | break; 461 | 462 | default: 463 | throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); 464 | } 465 | 466 | switch (parity) { 467 | case PARITY_NONE: 468 | lineRequestData[5] = 0; 469 | break; 470 | 471 | case PARITY_ODD: 472 | lineRequestData[5] = 1; 473 | break; 474 | 475 | case PARITY_EVEN: 476 | lineRequestData[5] = 2; 477 | break; 478 | 479 | case PARITY_MARK: 480 | lineRequestData[5] = 3; 481 | break; 482 | 483 | case PARITY_SPACE: 484 | lineRequestData[5] = 4; 485 | break; 486 | 487 | default: 488 | throw new IllegalArgumentException("Unknown parity value: " + parity); 489 | } 490 | 491 | lineRequestData[6] = (byte) dataBits; 492 | 493 | ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData); 494 | 495 | resetDevice(); 496 | 497 | mBaudRate = baudRate; 498 | mDataBits = dataBits; 499 | mStopBits = stopBits; 500 | mParity = parity; 501 | } 502 | 503 | @Override 504 | public boolean getCD() throws IOException { 505 | return testStatusFlag(STATUS_FLAG_CD); 506 | } 507 | 508 | @Override 509 | public boolean getCTS() throws IOException { 510 | return testStatusFlag(STATUS_FLAG_CTS); 511 | } 512 | 513 | @Override 514 | public boolean getDSR() throws IOException { 515 | return testStatusFlag(STATUS_FLAG_DSR); 516 | } 517 | 518 | @Override 519 | public boolean getDTR() throws IOException { 520 | return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR); 521 | } 522 | 523 | @Override 524 | public void setDTR(boolean value) throws IOException { 525 | int newControlLinesValue; 526 | if (value) { 527 | newControlLinesValue = mControlLinesValue | CONTROL_DTR; 528 | } else { 529 | newControlLinesValue = mControlLinesValue & ~CONTROL_DTR; 530 | } 531 | setControlLines(newControlLinesValue); 532 | } 533 | 534 | @Override 535 | public boolean getRI() throws IOException { 536 | return testStatusFlag(STATUS_FLAG_RI); 537 | } 538 | 539 | @Override 540 | public boolean getRTS() throws IOException { 541 | return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS); 542 | } 543 | 544 | @Override 545 | public void setRTS(boolean value) throws IOException { 546 | int newControlLinesValue; 547 | if (value) { 548 | newControlLinesValue = mControlLinesValue | CONTROL_RTS; 549 | } else { 550 | newControlLinesValue = mControlLinesValue & ~CONTROL_RTS; 551 | } 552 | setControlLines(newControlLinesValue); 553 | } 554 | 555 | @Override 556 | public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException { 557 | if (purgeReadBuffers) { 558 | vendorOut(FLUSH_RX_REQUEST, 0, null); 559 | } 560 | 561 | if (purgeWriteBuffers) { 562 | vendorOut(FLUSH_TX_REQUEST, 0, null); 563 | } 564 | 565 | return purgeReadBuffers || purgeWriteBuffers; 566 | } 567 | } 568 | 569 | public static Map getSupportedDevices() { 570 | final Map supportedDevices = new LinkedHashMap(); 571 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC), 572 | new int[] { UsbId.PROLIFIC_PL2303, }); 573 | return supportedDevices; 574 | } 575 | } 576 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | --------------------------------------------------------------------------------