Merge pull request #1 from mik3y/master

Update from upstream
This commit is contained in:
TVa[TIS] 2019-10-28 13:16:12 +01:00 committed by GitHub
commit e20b3cc913
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 2151 additions and 717 deletions

4
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
caches
codeStyles
libraries
workspace.xml

View File

@ -1 +0,0 @@
usb-serial-for-android

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

View File

@ -1,38 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="12">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="android.annotation.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="11">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="android.annotation.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.8</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

305
README.md
View File

@ -1,143 +1,162 @@
# usb-serial-for-android
This is a driver library for communication with Arduinos and other USB serial hardware on
Android, using the
[Android USB Host API](http://developer.android.com/guide/topics/connectivity/usb/host.html)
available on Android 3.1+.
No root access, ADK, or special kernel drivers are required; all drivers are implemented in
Java. You get a raw serial port with `read()`, `write()`, and other basic
functions for use with your own protocols.
* **Homepage**: https://github.com/mik3y/usb-serial-for-android
* **Google group**: http://groups.google.com/group/usb-serial-for-android
* **Latest release**: [v0.1.0](https://github.com/mik3y/usb-serial-for-android/releases)
## Quick Start
**1.** [Link your project](https://github.com/mik3y/usb-serial-for-android/wiki/Building-From-Source) to the library.
**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.
**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).
```xml
<activity
android:name="..."
...>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
```
**4.** Use it! Example code snippet:
```java
// Find all available drivers from attached devices.
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
return;
}
// Open a connection to the first available driver.
UsbSerialDriver driver = availableDrivers.get(0);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
// You probably need to call UsbManager.requestPermission(driver.getDevice(), ..)
return;
}
// Read some data! Most have just one port (port 0).
UsbSerialPort port = driver.getPorts().get(0);
try {
port.open(connection);
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
byte buffer[] = new byte[16];
int numBytesRead = port.read(buffer, 1000);
Log.d(TAG, "Read " + numBytesRead + " bytes.");
} catch (IOException e) {
// Deal with error.
} finally {
port.close();
}
```
For a more complete example, see the
[UsbSerialExamples project](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
in git, which is a simple application for reading and showing serial data.
A [simple Arduino application](https://github.com/mik3y/usb-serial-for-android/blob/master/arduino)
is also available which can be used for testing.
## Probing for Unrecognized Devices
Sometimes you may need to do a little extra work to support devices which
usb-serial-for-android doesn't [yet] know about -- but which you know to be
compatible with one of the built-in drivers. This may be the case for a brand
new device or for one using a custom VID/PID pair.
UsbSerialProber is a class to help you find and instantiate compatible
UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use
the default prober returned by ``UsbSerialProber.getDefaultProber()``, which
uses the built-in list of well-known VIDs and PIDs that are supported by our
drivers.
To use your own set of rules, create and use a custom prober:
```java
// Probe for our custom CDC devices, which use VID 0x1234
// and PIDS 0x0001 and 0x0002.
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class);
customTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);
// ...
```
Of course, nothing requires you to use UsbSerialProber at all: you can
instantiate driver classes directly if you know what you're doing; just supply
a compatible UsbDevice.
## Compatible Devices
* *Serial chips:* FT232R, CDC/ACM (eg Arduino Uno) and possibly others.
See [CompatibleSerialDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Serial-Devices).
* *Android phones and tablets:* Nexus 7, Motorola Xoom, and many others.
See [CompatibleAndroidDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Android-Devices).
## Author, License, and Copyright
usb-serial-for-android is written and maintained by *mike wakerly*.
This library is licensed under *LGPL Version 2.1*. Please see LICENSE.txt for the
complete license.
Copyright 2011-2012, Google Inc. All Rights Reserved.
Portions of this library are based on libftdi
(http://www.intra2net.com/en/developer/libftdi). Please see
FtdiSerialDriver.java for more information.
## Help & Discussion
For common problems, see the
[Troubleshooting](https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting)
wiki page.
For other help and discussion, please join our Google Group,
[usb-serial-for-android](https://groups.google.com/forum/?fromgroups#!forum/usb-serial-for-android).
Are you using the library? Let us know on the group and we'll add your project to
[ProjectsUsingUsbSerialForAndroid](https://github.com/mik3y/usb-serial-for-android/wiki/Projects-Using-usb-serial-for-android).
[![Jitpack](https://jitpack.io/v/mik3y/usb-serial-for-android.svg)](https://jitpack.io/#mik3y/usb-serial-for-android)
[![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&amp;utm_medium=referral&amp;utm_content=mik3y/usb-serial-for-android&amp;utm_campaign=Badge_Grade)
[![codecov](https://codecov.io/gh/mik3y/usb-serial-for-android/branch/master/graph/badge.svg)](https://codecov.io/gh/mik3y/usb-serial-for-android)
# usb-serial-for-android
This is a driver library for communication with Arduinos and other USB serial hardware on
Android, using the
[Android USB Host Mode (OTG)](http://developer.android.com/guide/topics/connectivity/usb/host.html)
available since Android 3.1 and working reliably since Android 4.2.
No root access, ADK, or special kernel drivers are required; all drivers are implemented in
Java. You get a raw serial port with `read()`, `write()`, and other basic
functions for use with your own protocols.
## Quick Start
**1.** Add library to your project:
Add jitpack.io repository to your root build.gradle:
```gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
```
Add library to dependencies
```gradle
dependencies {
implementation 'com.github.mik3y:usb-serial-for-android:Tag'
}
```
**2.** If the app should be notified when a device is attached, add
[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 and configure in your `AndroidManifest.xml`.
```xml
<activity
android:name="..."
...>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
```
**3.** Use it! Example code snippet:
```java
// Find all available drivers from attached devices.
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
return;
}
// Open a connection to the first available driver.
UsbSerialDriver driver = availableDrivers.get(0);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
// add UsbManager.requestPermission(driver.getDevice(), ..) handling here
return;
}
UsbSerialPort port = driver.getPorts().get(0); // Most devices have just one port (port 0)
port.open(connection);
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
Executors.newSingleThreadExecutor().submit(usbIoManager);
```
```java
port.write("hello".getBytes(), WRITE_WAIT_MILLIS);
```
```java
@Override
public void onNewData(byte[] data) {
runOnUiThread(() -> { textView.append(new String(data)); });
}
```
```java
port.close();
```
For a simple example, see
[UsbSerialExamples](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
folder in this project.
For a more complete example, see separate github project
[SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal).
## Probing for Unrecognized Devices
Sometimes you may need to do a little extra work to support devices which
usb-serial-for-android doesn't (yet) know about -- but which you know to be
compatible with one of the built-in drivers. This may be the case for a brand
new device or for one using a custom VID/PID pair.
UsbSerialProber is a class to help you find and instantiate compatible
UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use
the default prober returned by ``UsbSerialProber.getDefaultProber()``, which
uses the built-in list of well-known VIDs and PIDs that are supported by our
drivers.
To use your own set of rules, create and use a custom prober:
```java
// Probe for our custom CDC devices, which use VID 0x1234
// and PIDS 0x0001 and 0x0002.
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class);
customTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);
// ...
```
Of course, nothing requires you to use UsbSerialProber at all: you can
instantiate driver classes directly if you know what you're doing; just supply
a compatible UsbDevice.
## Compatible Devices
This library supports USB to serial converter chips:
* FTDI FT232, FT2232, ...
* Prolific PL2303
* Silabs CP2102, CP2105, ...
* Qinheng CH340
and devices implementing the CDC/ACM protocol like
* Arduino using ATmega32U4
* Digispark using V-USB software USB
* BBC micro:bit using ARM mbed DAPLink firmware
* ...
## Author, License, and Copyright
usb-serial-for-android is written and maintained by *mike wakerly* and *kai morich*
This library is licensed under *LGPL Version 2.1*. Please see LICENSE.txt for the
complete license.
Copyright 2011-2012, Google Inc. All Rights Reserved.
Portions of this library are based on [libftdi](http://www.intra2net.com/en/developer/libftdi).
Please see FtdiSerialDriver.java for more information.
## Help & Discussion
For common problems, see the
[Troubleshooting](https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting)
wiki page.
Are you using the library? Add your project to
[ProjectsUsingUsbSerialForAndroid](https://github.com/mik3y/usb-serial-for-android/wiki/Projects-Using-usb-serial-for-android).

View File

@ -1,43 +0,0 @@
/* Copyright 2012 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
// Sample Arduino sketch for use with usb-serial-for-android.
// Prints an ever-increasing counter, and writes back anything
// it receives.
static int counter = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print("Tick #");
Serial.print(counter++, DEC);
Serial.print("\n");
if (Serial.peek() != -1) {
Serial.print("Read: ");
do {
Serial.print((char) Serial.read());
} while (Serial.peek() != -1);
Serial.print("\n");
}
delay(1000);
}

View File

@ -2,15 +2,17 @@
buildscript {
repositories {
mavenCentral()
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'com.android.tools.build:gradle:3.5.1'
}
}
allprojects {
repositories {
mavenCentral()
jcenter()
google()
}
}

Binary file not shown.

View File

@ -1,6 +1,6 @@
#Tue Jun 23 00:11:28 EDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
#Sun Oct 06 09:46:24 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

126
gradlew vendored
View File

@ -1,4 +1,20 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
@ -6,47 +22,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@ -61,9 +36,49 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -90,7 +105,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@ -114,6 +129,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@ -154,11 +170,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

30
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -8,14 +24,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@ -46,10 +62,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@ -60,11 +75,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@ -0,0 +1,64 @@
/*
bridge USB-serial to hardware-serial
for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro)
hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB
see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino
-> CDC.cpp|HardwareSerial.cpp for serial implementation details
this sketch is mainly for demonstration / test of CDC communication
performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet
*/
uint32_t baud = 9600;
uint8_t databits = 8;
uint8_t stopbits = 1;
uint8_t parity = 0;
void setup() {
Serial.begin(baud); // USB
Serial1.begin(baud, SERIAL_8N1);
}
void loop() {
// show USB connected state
if (Serial) TXLED1;
else TXLED0;
// configure hardware serial
if (Serial.baud() != baud ||
Serial.numbits() != databits ||
Serial.stopbits() != stopbits ||
Serial.paritytype() != parity) {
baud = Serial.baud();
databits = Serial.numbits();
stopbits = Serial.stopbits();
parity = Serial.paritytype();
uint8_t config = 0; // ucsrc register
switch (databits) {
case 5: break;
case 6: config |= 2; break;
case 7: config |= 4; break;
case 8: config |= 6; break;
default: config |= 6;
}
switch (stopbits) {
case 2: config |= 8;
// 1.5 stopbits not supported
}
switch (parity) {
case 1: config |= 0x30; break; // odd
case 2: config |= 0x20; break; // even
// mark, space not supported
}
Serial1.end();
Serial1.begin(baud, config);
}
// bridge
if (Serial.available() > 0)
Serial1.write(Serial.read());
if (Serial1.available() > 0)
Serial.write(Serial1.read());
}

42
test/rfc2217_server.diff Normal file
View File

@ -0,0 +1,42 @@
*** /n/archiv/python/rfc2217_server.py 2018-03-10 09:02:07.613771600 +0100
--- rfc2217_server.py 2018-03-09 20:57:44.933717100 +0100
***************
*** 26,31 ****
--- 26,32 ----
self,
logger=logging.getLogger('rfc2217.server') if debug else None)
self.log = logging.getLogger('redirector')
+ self.dlog = logging.getLogger('data')
def statusline_poller(self):
self.log.debug('status line poll thread started')
***************
*** 55,60 ****
--- 56,62 ----
try:
data = self.serial.read(self.serial.in_waiting or 1)
if data:
+ self.dlog.debug("serial read: "+data.encode('hex'))
# escape outgoing data when needed (Telnet IAC (0xff) character)
self.write(b''.join(self.rfc2217.escape(data)))
except socket.error as msg:
***************
*** 76,81 ****
--- 78,84 ----
data = self.socket.recv(1024)
if not data:
break
+ self.dlog.debug("socket read: "+data.encode('hex'))
self.serial.write(b''.join(self.rfc2217.filter(data)))
except socket.error as msg:
self.log.error('{}'.format(msg))
***************
*** 132,137 ****
--- 135,141 ----
logging.basicConfig(level=logging.INFO)
#~ logging.getLogger('root').setLevel(logging.INFO)
logging.getLogger('rfc2217').setLevel(level)
+ logging.getLogger('data').setLevel(level)
# connect to serial port
ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True)

View File

@ -1,15 +1,15 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 14
targetSdkVersion 22
minSdkVersion 17
targetSdkVersion 28
testApplicationId "com.hoho.android.usbserial.examples"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
missingDimensionStrategy 'device', 'anyDevice'
}
buildTypes {
@ -20,5 +20,5 @@ android {
}
dependencies {
compile project(':usbSerialForAndroid')
implementation project(':usbSerialForAndroid')
}

View File

@ -4,8 +4,6 @@
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="12" />
<uses-feature android:name="android.hardware.usb.host" />
<application

View File

@ -22,7 +22,11 @@
package com.hoho.android.usbserial.examples;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
@ -39,12 +43,12 @@ import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.TwoLineListItem;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.HexDump;
import java.util.ArrayList;
import java.util.List;
@ -59,12 +63,14 @@ public class DeviceListActivity extends Activity {
private final String TAG = DeviceListActivity.class.getSimpleName();
private UsbManager mUsbManager;
private UsbSerialPort mSerialPort;
private ListView mListView;
private TextView mProgressBarTitle;
private ProgressBar mProgressBar;
private static final int MESSAGE_REFRESH = 101;
private static final long REFRESH_TIMEOUT_MILLIS = 5000;
public static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
private final Handler mHandler = new Handler() {
@Override
@ -81,6 +87,7 @@ public class DeviceListActivity extends Activity {
}
};
private BroadcastReceiver mUsbReceiver;
private List<UsbSerialPort> mEntries = new ArrayList<UsbSerialPort>();
private ArrayAdapter<UsbSerialPort> mAdapter;
@ -89,11 +96,25 @@ public class DeviceListActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Context context = this;
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
mListView = (ListView) findViewById(R.id.deviceList);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mProgressBarTitle = (TextView) findViewById(R.id.progressBarTitle);
mListView = findViewById(R.id.deviceList);
mProgressBar = findViewById(R.id.progressBar);
mProgressBarTitle = findViewById(R.id.progressBarTitle);
mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(INTENT_ACTION_GRANT_USB)) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
showConsoleActivity(mSerialPort);
} else {
Toast.makeText(context, "USB permission denied", Toast.LENGTH_SHORT).show();
}
}
}
};
mAdapter = new ArrayAdapter<UsbSerialPort>(this,
android.R.layout.simple_expandable_list_item_2, mEntries) {
@ -112,9 +133,7 @@ public class DeviceListActivity extends Activity {
final UsbSerialDriver driver = port.getDriver();
final UsbDevice device = driver.getDevice();
final String title = String.format("Vendor %s Product %s",
HexDump.toHexString((short) device.getVendorId()),
HexDump.toHexString((short) device.getProductId()));
final String title = String.format("Vendor %4X Product %4X", device.getVendorId(), device.getProductId());
row.getText1().setText(title);
final String subtitle = driver.getClass().getSimpleName();
@ -135,8 +154,14 @@ public class DeviceListActivity extends Activity {
return;
}
final UsbSerialPort port = mEntries.get(position);
showConsoleActivity(port);
mSerialPort = mEntries.get(position);
UsbDevice device = mSerialPort.getDriver().getDevice();
if (!mUsbManager.hasPermission(device)) {
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
mUsbManager.requestPermission(device, usbPermissionIntent);
} else {
showConsoleActivity(mSerialPort);
}
}
});
}
@ -145,12 +170,14 @@ public class DeviceListActivity extends Activity {
protected void onResume() {
super.onResume();
mHandler.sendEmptyMessage(MESSAGE_REFRESH);
registerReceiver(mUsbReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
}
@Override
protected void onPause() {
super.onPause();
mHandler.removeMessages(MESSAGE_REFRESH);
unregisterReceiver(mUsbReceiver);
}
private void refreshDeviceList() {

View File

@ -1,14 +1,17 @@
apply plugin: 'com.android.library'
apply plugin: 'maven'
apply plugin: 'signing'
android {
compileSdkVersion 19
buildToolsVersion "19.1"
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 12
targetSdkVersion 19
minSdkVersion 17
targetSdkVersion 28
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ...
'rfc2217_server_host': '192.168.0.100',
'rfc2217_server_nonstandard_baudrates': 'true', // true false false
]
}
buildTypes {
@ -19,81 +22,14 @@ android {
}
}
group = "com.hoho.android"
version = "0.2.0-SNAPSHOT"
configurations {
archives {
extendsFrom configurations.default
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support:support-annotations:28.0.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'commons-net:commons-net:3.6'
androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1'
}
signing {
required { has("release") && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
//apply from: 'publishToMavenLocal.gradle'
def getRepositoryUsername() {
return hasProperty('sonatypeUsername') ? sonatypeUsername : ""
}
def getRepositoryPassword() {
return hasProperty('sonatypePassword') ? sonatypePassword : ""
}
def isReleaseBuild() {
return version.contains("SNAPSHOT") == false
}
uploadArchives {
def sonatypeRepositoryUrl
if (isReleaseBuild()) {
println 'RELEASE BUILD'
sonatypeRepositoryUrl = hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
} else {
println 'SNAPSHOT BUILD'
sonatypeRepositoryUrl = hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
: "https://oss.sonatype.org/content/repositories/snapshots/"
}
configuration = configurations.archives
repositories.mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: sonatypeRepositoryUrl) {
authentication(userName: getRepositoryUsername(),
password: getRepositoryPassword())
}
pom.artifactId = 'usb-serial-for-android'
pom.project {
name 'usb-serial-for-android'
packaging 'aar'
description 'USB Serial Driver Library for Android'
url 'https://github.com/mik3y/usb-serial-for-android'
scm {
url 'scm:git@github.com:mik3y/usb-serial-for-android.git'
connection 'scm:git@github.com:mik3y/usb-serial-for-android.git'
developerConnection 'scm:git@github.com:mik3y/usb-serial-for-android.git'
}
licenses {
license {
name 'GNU LGPL v2.1'
url 'http://www.gnu.org/licenses/lgpl-2.1.txt'
distribution 'repo'
}
}
developers {
developer {
id 'mik3y'
name 'mik3y'
email 'opensource@hoho.com'
}
}
}
}
}
//apply from: 'coverage.gradle'

View File

@ -0,0 +1,45 @@
apply plugin: 'jacoco'
android {
flavorDimensions 'device'
productFlavors {
anyDevice {
// Used as fallback in usbSerialExample/build.gradle -> missingDimensionStrategy, but not for coverage report
dimension 'device'
}
arduino {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'CdcAcm']
}
ch340 {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Ch34x']
}
cp2102 { // and cp2105 first port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Cp21xx']
}
cp2105 { // second port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Cp21xx', 'test_device_port': '1']
}
ft232 { // and ft2232 first port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Ftdi']
}
ft2232 { // second port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Ftdi', 'test_device_port': '1']
}
pl2302 {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Prolific']
}
}
buildTypes {
debug {
testCoverageEnabled true
}
}
}

View File

@ -0,0 +1,20 @@
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
groupId 'com.github.mik3y'
artifactId 'usb-serial-for-android'
version '1.x.0'
afterEvaluate {
artifact androidSourcesJar
artifact bundleReleaseAar
}
}
}
}
task androidSourcesJar(type: Jar) {
classifier 'sources'
from android.sourceSets.main.java.srcDirs
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hoho.android.usbserial"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hoho.android.usbserial"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="12" />
package="com.hoho.android.usbserial">
</manifest>

View File

@ -1,19 +0,0 @@
package com.hoho.android.usbserial;
/**
* Static container of information about this library.
*/
public final class BuildInfo {
/**
* The current version of this library. Values are of the form
* "major.minor.micro[-suffix]". A suffix of "-pre" indicates a pre-release
* of the version preceeding it.
*/
public static final String VERSION = "0.2.0-pre";
private BuildInfo() {
throw new IllegalStateException("Non-instantiable class.");
}
}

View File

@ -27,7 +27,6 @@ import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.os.Build;
import android.util.Log;
import java.io.IOException;
@ -51,6 +50,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
private UsbRequest mUsbRequest;
public CdcAcmSerialDriver(UsbDevice device) {
mDevice = device;
@ -69,7 +69,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
class CdcAcmSerialPort extends CommonUsbSerialPort {
private final boolean mEnableAsyncReads;
private UsbInterface mControlInterface;
private UsbInterface mDataInterface;
@ -77,6 +76,8 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private int mControlIndex;
private boolean mRts = false;
private boolean mDtr = false;
@ -90,7 +91,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
public CdcAcmSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
}
@Override
@ -116,13 +116,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
openInterface();
}
if (mEnableAsyncReads) {
Log.d(TAG, "Async reads enabled");
} else {
Log.d(TAG, "Async reads disabled.");
}
opened = true;
} finally {
if (!opened) {
@ -139,6 +132,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
// the following code is inspired by the cdc-acm driver
// in the linux kernel
mControlIndex = 0;
mControlInterface = mDevice.getInterface(0);
Log.d(TAG, "Control iface=" + mControlInterface);
@ -196,34 +190,63 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
private void openInterface() throws IOException {
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
mControlInterface = mDevice.getInterface(0);
mControlInterface = null;
mDataInterface = null;
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbInterface = mDevice.getInterface(i);
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM) {
mControlIndex = i;
mControlInterface = usbInterface;
}
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
mDataInterface = usbInterface;
}
}
if(mControlInterface == null) {
throw new IOException("no control interface.");
}
Log.d(TAG, "Control iface=" + mControlInterface);
// class should be USB_CLASS_COMM
if (!mConnection.claimInterface(mControlInterface, true)) {
throw new IOException("Could not claim control interface.");
}
mControlEndpoint = mControlInterface.getEndpoint(0);
Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) {
throw new IOException("invalid control endpoint");
}
Log.d(TAG, "Claiming data interface.");
mDataInterface = mDevice.getInterface(1);
if(mDataInterface == null) {
throw new IOException("no data interface.");
}
Log.d(TAG, "data iface=" + mDataInterface);
// class should be USB_CLASS_CDC_DATA
if (!mConnection.claimInterface(mDataInterface, true)) {
throw new IOException("Could not claim data interface.");
}
mReadEndpoint = mDataInterface.getEndpoint(1);
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
mWriteEndpoint = mDataInterface.getEndpoint(0);
Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
mReadEndpoint = null;
mWriteEndpoint = null;
for (int i = 0; i < mDataInterface.getEndpointCount(); i++) {
UsbEndpoint ep = mDataInterface.getEndpoint(i);
if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
mReadEndpoint = ep;
if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
mWriteEndpoint = ep;
}
if (mReadEndpoint == null || mWriteEndpoint == null) {
throw new IOException("Could not get read&write endpoints.");
}
}
private int sendAcmControlMessage(int request, int value, byte[] buf) {
return mConnection.controlTransfer(
USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException {
int len = mConnection.controlTransfer(
USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000);
if(len < 0) {
throw new IOException("controlTransfer failed.");
}
return len;
}
@Override
@ -231,57 +254,43 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
if (mConnection == null) {
throw new IOException("Already closed");
}
synchronized (this) {
if (mUsbRequest != null)
mUsbRequest.cancel();
}
mConnection.close();
mConnection = null;
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
if (mEnableAsyncReads) {
final UsbRequest request = new UsbRequest();
try {
final UsbRequest request = new UsbRequest();
try {
request.initialize(mConnection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
throw new IOException("Error queueing request.");
}
mUsbRequest = request;
final UsbRequest response = mConnection.requestWait();
synchronized (this) {
mUsbRequest = null;
}
if (response == null) {
throw new IOException("Null response");
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
} finally {
request.close();
}
}
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
if (timeoutMillis == Integer.MAX_VALUE) {
// Hack: Special case "~infinite timeout" as an error.
return -1;
}
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
} finally {
mUsbRequest = null;
request.close();
}
return numBytesRead;
}
@Override
@ -320,7 +329,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) {
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
byte stopBitsByte;
switch (stopBits) {
case STOPBITS_1: stopBitsByte = 0; break;
@ -392,7 +401,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
setDtrRts();
}
private void setDtrRts() {
private void setDtrRts() throws IOException {
int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
}
@ -401,7 +410,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),
supportedDevices.put(UsbId.VENDOR_ARDUINO,
new int[] {
UsbId.ARDUINO_UNO,
UsbId.ARDUINO_UNO_R3,
@ -414,18 +423,22 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
UsbId.ARDUINO_LEONARDO,
UsbId.ARDUINO_MICRO,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),
supportedDevices.put(UsbId.VENDOR_VAN_OOIJEN_TECH,
new int[] {
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL),
supportedDevices.put(UsbId.VENDOR_ATMEL,
new int[] {
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS),
supportedDevices.put(UsbId.VENDOR_LEAFLABS,
new int[] {
UsbId.LEAFLABS_MAPLE,
});
supportedDevices.put(UsbId.VENDOR_ARM,
new int[] {
UsbId.ARM_MBED,
});
return supportedDevices;
}

View File

@ -25,9 +25,11 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@ -46,6 +48,17 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
private static final int LCR_ENABLE_RX = 0x80;
private static final int LCR_ENABLE_TX = 0x40;
private static final int LCR_MARK_SPACE = 0x20;
private static final int LCR_PAR_EVEN = 0x10;
private static final int LCR_ENABLE_PAR = 0x08;
private static final int LCR_STOP_BITS_2 = 0x04;
private static final int LCR_CS8 = 0x03;
private static final int LCR_CS7 = 0x02;
private static final int LCR_CS6 = 0x01;
private static final int LCR_CS5 = 0x00;
public Ch34xSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new Ch340SerialPort(mDevice, 0);
@ -72,6 +85,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private UsbRequest mUsbRequest;
public Ch340SerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
@ -93,10 +107,8 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbIface = mDevice.getInterface(i);
if (mConnection.claimInterface(usbIface, true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
Log.d(TAG, "claimInterface " + i + " FAIL");
if (!mConnection.claimInterface(usbIface, true)) {
throw new IOException("Could not claim data interface.");
}
}
@ -112,7 +124,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
}
}
initialize();
setBaudRate(DEFAULT_BAUD_RATE);
@ -133,9 +144,10 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
if (mConnection == null) {
throw new IOException("Already closed");
}
// TODO: nothing sended on close, maybe needed?
synchronized (this) {
if (mUsbRequest != null)
mUsbRequest.cancel();
}
try {
mConnection.close();
} finally {
@ -146,21 +158,33 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
final UsbRequest request = new UsbRequest();
try {
request.initialize(mConnection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
mUsbRequest = request;
final UsbRequest response = mConnection.requestWait();
synchronized (this) {
mUsbRequest = null;
}
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
} finally {
mUsbRequest = null;
request.close();
}
return numBytesRead;
}
@Override
@ -252,7 +276,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
if (controlOut(0x9a, 0x2518, 0x0050) < 0) {
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
throw new IOException("init failed! #5");
}
@ -271,36 +295,93 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
private void setBaudRate(int baudRate) throws IOException {
int[] baud = new int[]{2400, 0xd901, 0x0038, 4800, 0x6402,
0x001f, 9600, 0xb202, 0x0013, 19200, 0xd902, 0x000d, 38400,
0x6403, 0x000a, 115200, 0xcc03, 0x0008};
final long CH341_BAUDBASE_FACTOR = 1532620800;
final int CH341_BAUDBASE_DIVMAX = 3;
for (int i = 0; i < baud.length / 3; i++) {
if (baud[i * 3] == baudRate) {
int ret = controlOut(0x9a, 0x1312, baud[i * 3 + 1]);
if (ret < 0) {
throw new IOException("Error setting baud rate. #1");
}
ret = controlOut(0x9a, 0x0f2c, baud[i * 3 + 2]);
if (ret < 0) {
throw new IOException("Error setting baud rate. #1");
long factor = CH341_BAUDBASE_FACTOR / baudRate;
int divisor = CH341_BAUDBASE_DIVMAX;
while ((factor > 0xfff0) && divisor > 0) {
factor >>= 3;
divisor--;
}
return;
}
if (factor > 0xfff0) {
throw new IOException("Baudrate " + baudRate + " not supported");
}
factor = 0x10000 - factor;
throw new IOException("Baud rate " + baudRate + " currently not supported");
int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor));
if (ret < 0) {
throw new IOException("Error setting baud rate. #1)");
}
ret = controlOut(0x9a, 0x0f2c, (int) (factor & 0xff));
if (ret < 0) {
throw new IOException("Error setting baud rate. #2");
}
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
throws IOException {
setBaudRate(baudRate);
// TODO databit, stopbit and paraty set not implemented
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
switch (dataBits) {
case DATABITS_5:
lcr |= LCR_CS5;
break;
case DATABITS_6:
lcr |= LCR_CS6;
break;
case DATABITS_7:
lcr |= LCR_CS7;
break;
case DATABITS_8:
lcr |= LCR_CS8;
break;
default:
throw new IllegalArgumentException("Unknown dataBits value: " + dataBits);
}
switch (parity) {
case PARITY_NONE:
break;
case PARITY_ODD:
lcr |= LCR_ENABLE_PAR;
break;
case PARITY_EVEN:
lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN;
break;
case PARITY_MARK:
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE;
break;
case PARITY_SPACE:
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN;
break;
default:
throw new IllegalArgumentException("Unknown parity value: " + parity);
}
switch (stopBits) {
case STOPBITS_1:
break;
case STOPBITS_1_5:
throw new IllegalArgumentException("Unsupported stopBits value: 1.5");
case STOPBITS_2:
lcr |= LCR_STOP_BITS_2;
break;
default:
throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
int ret = controlOut(0x9a, 0x2518, lcr);
if (ret < 0) {
throw new IOException("Error setting control byte");
}
}
@Override
@ -345,11 +426,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
writeHandshakeByte();
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
return true;
}
}
public static Map<Integer, int[]> getSupportedDevices() {

View File

@ -160,8 +160,8 @@ abstract class CommonUsbSerialPort implements UsbSerialPort {
public abstract void setRTS(boolean value) throws IOException;
@Override
public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException {
return !flushReadBuffers && !flushWriteBuffers;
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
return false;
}
}

View File

@ -26,10 +26,12 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import java.io.IOException;
import java.util.Collections;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -39,11 +41,14 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
private final List<UsbSerialPort> mPorts;
public Cp21xxSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new Cp21xxSerialPort(mDevice, 0);
mPorts = new ArrayList<>();
for( int port = 0; port < device.getInterfaceCount(); port++) {
mPorts.add(new Cp21xxSerialPort(mDevice, port));
}
}
@Override
@ -53,7 +58,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
@Override
public List<UsbSerialPort> getPorts() {
return Collections.singletonList(mPort);
return mPorts;
}
public class Cp21xxSerialPort extends CommonUsbSerialPort {
@ -103,6 +108,11 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private UsbRequest mUsbRequest;
// second port of Cp2105 has limited baudRate, dataBits, stopBits, parity
// unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored
private boolean mIsRestrictedPort;
public Cp21xxSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
@ -115,7 +125,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
private int setConfigSingle(int request, int value) {
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,
0, null, 0, USB_WRITE_TIMEOUT_MILLIS);
mPortNumber, null, 0, USB_WRITE_TIMEOUT_MILLIS);
}
@Override
@ -126,17 +136,15 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
mConnection = connection;
boolean opened = false;
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbIface = mDevice.getInterface(i);
if (mConnection.claimInterface(usbIface, true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
Log.d(TAG, "claimInterface " + i + " FAIL");
}
if(mPortNumber >= mDevice.getInterfaceCount()) {
throw new IOException("Unknown port number");
}
UsbInterface dataIface = mDevice.getInterface(mPortNumber);
if (!mConnection.claimInterface(dataIface, true)) {
throw new IOException("Could not claim interface " + mPortNumber);
}
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
UsbEndpoint ep = dataIface.getEndpoint(i);
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
@ -169,8 +177,16 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
if (mConnection == null) {
throw new IOException("Already closed");
}
synchronized (this) {
if(mUsbRequest != null) {
mUsbRequest.cancel();
}
}
try {
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
} catch (Exception ignored)
{}
try {
mConnection.close();
} finally {
mConnection = null;
@ -179,21 +195,33 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
final UsbRequest request = new UsbRequest();
try {
request.initialize(mConnection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
mUsbRequest = request;
final UsbRequest response = mConnection.requestWait();
synchronized (this) {
mUsbRequest = null;
}
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
} finally {
mUsbRequest = null;
request.close();
}
return numBytesRead;
}
@Override
@ -238,7 +266,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
(byte) ((baudRate >> 24) & 0xff)
};
int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
0, 0, data, 4, USB_WRITE_TIMEOUT_MILLIS);
0, mPortNumber, data, 4, USB_WRITE_TIMEOUT_MILLIS);
if (ret < 0) {
throw new IOException("Error setting baud rate.");
}
@ -252,38 +280,62 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
int configDataBits = 0;
switch (dataBits) {
case DATABITS_5:
if(mIsRestrictedPort)
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
configDataBits |= 0x0500;
break;
case DATABITS_6:
if(mIsRestrictedPort)
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
configDataBits |= 0x0600;
break;
case DATABITS_7:
if(mIsRestrictedPort)
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
configDataBits |= 0x0700;
break;
case DATABITS_8:
configDataBits |= 0x0800;
break;
default:
configDataBits |= 0x0800;
break;
throw new IllegalArgumentException("Unknown dataBits value: " + dataBits);
}
switch (parity) {
case PARITY_NONE:
break;
case PARITY_ODD:
configDataBits |= 0x0010;
break;
case PARITY_EVEN:
configDataBits |= 0x0020;
break;
case PARITY_MARK:
if(mIsRestrictedPort)
throw new IllegalArgumentException("Unsupported parity value: mark");
configDataBits |= 0x0030;
break;
case PARITY_SPACE:
if(mIsRestrictedPort)
throw new IllegalArgumentException("Unsupported parity value: space");
configDataBits |= 0x0040;
break;
default:
throw new IllegalArgumentException("Unknown parity value: " + parity);
}
switch (stopBits) {
case STOPBITS_1:
configDataBits |= 0;
break;
case STOPBITS_1_5:
throw new IllegalArgumentException("Unsupported stopBits value: 1.5");
case STOPBITS_2:
if(mIsRestrictedPort)
throw new IllegalArgumentException("Unsupported stopBits value: 2");
configDataBits |= 2;
break;
default:
throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
}
@ -327,8 +379,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers,
boolean purgeWriteBuffers) throws IOException {
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
| (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
@ -343,7 +394,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS),
supportedDevices.put(UsbId.VENDOR_SILABS,
new int[] {
UsbId.SILABS_CP2102,
UsbId.SILABS_CP2105,

View File

@ -28,11 +28,9 @@ import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import com.hoho.android.usbserial.util.HexDump;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -72,6 +70,8 @@ import java.util.Map;
* Supported and tested devices:
* <ul>
* <li>{@value DeviceType#TYPE_R}</li>
* <li>{@value DeviceType#TYPE_2232H}</li>
* <li>{@value DeviceType#TYPE_4232H}</li>
* </ul>
* </p>
* <p>
@ -79,8 +79,6 @@ import java.util.Map;
* feedback or patches):
* <ul>
* <li>{@value DeviceType#TYPE_2232C}</li>
* <li>{@value DeviceType#TYPE_2232H}</li>
* <li>{@value DeviceType#TYPE_4232H}</li>
* <li>{@value DeviceType#TYPE_AM}</li>
* <li>{@value DeviceType#TYPE_BM}</li>
* </ul>
@ -95,7 +93,7 @@ import java.util.Map;
public class FtdiSerialDriver implements UsbSerialDriver {
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
private final List<UsbSerialPort> mPorts;
/**
* FTDI chip types.
@ -106,8 +104,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
public FtdiSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new FtdiSerialPort(mDevice, 0);
mPorts = new ArrayList<>();
for( int port = 0; port < device.getInterfaceCount(); port++) {
mPorts.add(new FtdiSerialPort(mDevice, port));
}
}
@Override
public UsbDevice getDevice() {
return mDevice;
@ -115,7 +117,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
@Override
public List<UsbSerialPort> getPorts() {
return Collections.singletonList(mPort);
return mPorts;
}
private class FtdiSerialPort extends CommonUsbSerialPort {
@ -163,7 +165,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
private static final int SIO_SET_DATA_REQUEST = 4;
private static final int SIO_RESET_SIO = 0;
private static final int SIO_RESET_PURGE_RX = 1;
private static final int SIO_RESET_PURGE_RX = 1; // RX @ FTDI device = write @ usb-serial-for-android library
private static final int SIO_RESET_PURGE_TX = 2;
public static final int FTDI_DEVICE_OUT_REQTYPE =
@ -181,16 +183,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
private DeviceType mType;
private int mInterface = 0; /* INTERFACE_ANY */
private int mMaxPacketSize = 64; // TODO(mikey): detect
/**
* Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
* since it gives no indication of number of bytes read. Set this to
* {@code true} on platforms where it is fixed.
*/
private static final boolean ENABLE_ASYNC_READS = false;
private int mIndex = 0;
public FtdiSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
@ -210,10 +203,10 @@ public class FtdiSerialDriver implements UsbSerialDriver {
* @return The number of payload bytes
*/
private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) {
final int packetsCount = totalBytesRead / maxPacketSize + (totalBytesRead % maxPacketSize == 0 ? 0 : 1);
final int packetsCount = (totalBytesRead + maxPacketSize -1 )/ maxPacketSize;
for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) {
final int count = (packetIdx == (packetsCount - 1))
? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH
? totalBytesRead - packetIdx * maxPacketSize - MODEM_STATUS_HEADER_LENGTH
: maxPacketSize - MODEM_STATUS_HEADER_LENGTH;
if (count > 0) {
System.arraycopy(src,
@ -228,14 +221,21 @@ public class FtdiSerialDriver implements UsbSerialDriver {
}
public void reset() throws IOException {
// TODO(mikey): autodetect.
mType = DeviceType.TYPE_R;
if(mDevice.getInterfaceCount() > 1) {
mIndex = mPortNumber + 1;
if (mDevice.getInterfaceCount() == 2)
mType = DeviceType.TYPE_2232H;
if (mDevice.getInterfaceCount() == 4)
mType = DeviceType.TYPE_4232H;
}
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
SIO_RESET_SIO, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Reset failed: result=" + result);
}
// TODO(mikey): autodetect.
mType = DeviceType.TYPE_R;
}
@Override
@ -247,12 +247,10 @@ public class FtdiSerialDriver implements UsbSerialDriver {
boolean opened = false;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
if (connection.claimInterface(mDevice.getInterface(i), true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
throw new IOException("Error claiming interface " + i);
}
if (connection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
Log.d(TAG, "claimInterface " + mPortNumber + " SUCCESS");
} else {
throw new IOException("Error claiming interface " + mPortNumber);
}
reset();
opened = true;
@ -278,20 +276,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
if (ENABLE_ASYNC_READS) {
final int readAmt;
synchronized (mReadBufferLock) {
// mReadBuffer is only used for maximum read size.
readAmt = Math.min(dest.length, mReadBuffer.length);
}
final UsbRequest request = new UsbRequest();
final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(0);
final UsbRequest request = new UsbRequest();
final ByteBuffer buf = ByteBuffer.wrap(dest);
try {
request.initialize(mConnection, endpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, readAmt)) {
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
@ -299,34 +289,21 @@ public class FtdiSerialDriver implements UsbSerialDriver {
if (response == null) {
throw new IOException("Null response");
}
final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
if (payloadBytesRead > 0) {
Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return payloadBytesRead;
} else {
return 0;
}
} else {
final int totalBytesRead;
synchronized (mReadBufferLock) {
final int readAmt = Math.min(dest.length, mReadBuffer.length);
totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
readAmt, timeoutMillis);
if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
}
return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());
}
} finally {
request.close();
}
final int totalBytesRead = buf.position();
if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
}
return filterStatusBytes(dest, dest, totalBytesRead, endpoint.getMaxPacketSize());
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1);
final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(1);
int offset = 0;
while (offset < src.length) {
@ -379,7 +356,18 @@ public class FtdiSerialDriver implements UsbSerialDriver {
throws IOException {
setBaudRate(baudRate);
int config = dataBits;
int config = 0;
switch (dataBits) {
case DATABITS_5:
case DATABITS_6:
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
case DATABITS_7:
case DATABITS_8:
config |= dataBits;
break;
default:
throw new IllegalArgumentException("Unknown dataBits value: " + dataBits);
}
switch (parity) {
case PARITY_NONE:
@ -406,8 +394,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
config |= (0x00 << 11);
break;
case STOPBITS_1_5:
config |= (0x01 << 11);
break;
throw new IllegalArgumentException("Unsupported stopBits value: 1.5");
case STOPBITS_2:
config |= (0x02 << 11);
break;
@ -416,7 +403,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
}
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_DATA_REQUEST, config, 0 /* index */,
SIO_SET_DATA_REQUEST, config, mIndex,
null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Setting parameters failed: result=" + result);
@ -496,9 +483,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
long index;
if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
|| mType == DeviceType.TYPE_4232H) {
index = (encodedDivisor >> 8) & 0xffff;
index &= 0xFF00;
index |= 0 /* TODO mIndex */;
index = (encodedDivisor >> 8) & 0xff00;
index |= mIndex;
} else {
index = (encodedDivisor >> 16) & 0xffff;
}
@ -548,20 +534,20 @@ public class FtdiSerialDriver implements UsbSerialDriver {
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
if (purgeReadBuffers) {
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
if (purgeWriteBuffers) {
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_PURGE_RX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
SIO_RESET_PURGE_RX, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Flushing RX failed: result=" + result);
throw new IOException("purge write buffer failed: result=" + result);
}
}
if (purgeWriteBuffers) {
if (purgeReadBuffers) {
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_PURGE_TX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
SIO_RESET_PURGE_TX, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Flushing RX failed: result=" + result);
throw new IOException("purge read buffer failed: result=" + result);
}
}
return true;
@ -570,9 +556,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
supportedDevices.put(UsbId.VENDOR_FTDI,
new int[] {
UsbId.FTDI_FT232R,
UsbId.FTDI_FT232H,
UsbId.FTDI_FT2232H,
UsbId.FTDI_FT4232H,
UsbId.FTDI_FT231X,
});
return supportedDevices;

View File

@ -32,10 +32,12 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@ -86,7 +88,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
private static final int READ_ENDPOINT = 0x83;
private static final int INTERRUPT_ENDPOINT = 0x81;
private static final int FLUSH_RX_REQUEST = 0x08;
private static final int FLUSH_RX_REQUEST = 0x08; // RX @ Prolific device = write @ usb-serial-for-android library
private static final int FLUSH_TX_REQUEST = 0x09;
private static final int SET_LINE_REQUEST = 0x20;
@ -368,15 +370,28 @@ public class ProlificSerialDriver implements UsbSerialDriver {
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,
readAmt, timeoutMillis);
if (numBytesRead < 0) {
final UsbRequest request = new UsbRequest();
try {
request.initialize(mConnection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = mConnection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
return numBytesRead;
} finally {
request.close();
}
}
@ -538,22 +553,22 @@ public class ProlificSerialDriver implements UsbSerialDriver {
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
if (purgeReadBuffers) {
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
if (purgeWriteBuffers) {
vendorOut(FLUSH_RX_REQUEST, 0, null);
}
if (purgeWriteBuffers) {
if (purgeReadBuffers) {
vendorOut(FLUSH_TX_REQUEST, 0, null);
}
return purgeReadBuffers || purgeWriteBuffers;
return true;
}
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC),
supportedDevices.put(UsbId.VENDOR_PROLIFIC,
new int[] { UsbId.PROLIFIC_PL2303, });
return supportedDevices;
}

View File

@ -33,6 +33,9 @@ public final class UsbId {
public static final int VENDOR_FTDI = 0x0403;
public static final int FTDI_FT232R = 0x6001;
public static final int FTDI_FT2232H = 0x6010;
public static final int FTDI_FT4232H = 0x6011;
public static final int FTDI_FT232H = 0x6014;
public static final int FTDI_FT231X = 0x6015;
public static final int VENDOR_ATMEL = 0x03EB;
@ -68,6 +71,10 @@ public final class UsbId {
public static final int VENDOR_QINHENG = 0x1a86;
public static final int QINHENG_HL340 = 0x7523;
// at www.linux-usb.org/usb.ids listed for NXP/LPC1768, but all processors supported by ARM mbed DAPLink firmware report these ids
public static final int VENDOR_ARM = 0x0d28;
public static final int ARM_MBED = 0x0204;
private UsbId() {
throw new IllegalAccessError("Non-instantiable class.");
}

View File

@ -216,13 +216,13 @@ public interface UsbSerialPort {
public void setRTS(boolean value) throws IOException;
/**
* Flush non-transmitted output data and / or non-read input data
* @param flushRX {@code true} to flush non-transmitted output data
* @param flushTX {@code true} to flush non-read input data
* purge non-transmitted output data and / or non-read input data
* @param purgeWriteBuffers {@code true} to discard non-transmitted output data
* @param purgeReadBuffers {@code true} to discard non-read input data
* @return {@code true} if the operation was successful, or
* {@code false} if the operation is not supported by the driver or device
* @throws IOException if an error occurred during flush
*/
public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException;
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException;
}

View File

@ -1,46 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package com.hoho.android.usbserial.driver;
/**
* Generic unchecked exception for the usbserial package.
*
* @author mike wakerly (opensource@hoho.com)
*/
@SuppressWarnings("serial")
public class UsbSerialRuntimeException extends RuntimeException {
public UsbSerialRuntimeException() {
super();
}
public UsbSerialRuntimeException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
public UsbSerialRuntimeException(String detailMessage) {
super(detailMessage);
}
public UsbSerialRuntimeException(Throwable throwable) {
super(throwable);
}
}

View File

@ -50,7 +50,7 @@ public class SerialInputOutputManager implements Runnable {
// Synchronized by 'mWriteBuffer'
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private enum State {
public enum State {
STOPPED,
RUNNING,
STOPPING
@ -111,7 +111,7 @@ public class SerialInputOutputManager implements Runnable {
}
}
private synchronized State getState() {
public synchronized State getState() {
return mState;
}
@ -120,7 +120,6 @@ public class SerialInputOutputManager implements Runnable {
* called, or until a driver exception is raised.
*
* NOTE(mikey): Uses inefficient read/write-with-timeout.
* TODO(mikey): Read asynchronously with {@link UsbRequest#queue(ByteBuffer, int)}
*/
@Override
public void run() {