mirror of
https://github.com/mik3y/usb-serial-for-android
synced 2025-06-07 16:06:10 +00:00
commit
e20b3cc913
4
.idea/.gitignore
generated
vendored
Normal file
4
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
caches
|
||||||
|
codeStyles
|
||||||
|
libraries
|
||||||
|
workspace.xml
|
1
.idea/.name
generated
1
.idea/.name
generated
@ -1 +0,0 @@
|
|||||||
usb-serial-for-android
|
|
21
.idea/compiler.xml
generated
21
.idea/compiler.xml
generated
@ -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>
|
|
3
.idea/copyright/profiles_settings.xml
generated
3
.idea/copyright/profiles_settings.xml
generated
@ -1,3 +0,0 @@
|
|||||||
<component name="CopyrightManager">
|
|
||||||
<settings default="" />
|
|
||||||
</component>
|
|
68
.idea/misc.xml
generated
68
.idea/misc.xml
generated
@ -1,38 +1,48 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="EntryPointsManager">
|
<component name="NullableNotNullManager">
|
||||||
<entry_points version="2.0" />
|
<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>
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<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">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
<option name="id" value="Android" />
|
<option name="id" value="Android" />
|
||||||
</component>
|
</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>
|
</project>
|
12
.idea/runConfigurations.xml
generated
Normal file
12
.idea/runConfigurations.xml
generated
Normal 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
305
README.md
@ -1,143 +1,162 @@
|
|||||||
# usb-serial-for-android
|
[](https://jitpack.io/#mik3y/usb-serial-for-android)
|
||||||
|
[](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)
|
||||||
This is a driver library for communication with Arduinos and other USB serial hardware on
|
[](https://codecov.io/gh/mik3y/usb-serial-for-android)
|
||||||
Android, using the
|
|
||||||
[Android USB Host API](http://developer.android.com/guide/topics/connectivity/usb/host.html)
|
# usb-serial-for-android
|
||||||
available on Android 3.1+.
|
|
||||||
|
This is a driver library for communication with Arduinos and other USB serial hardware on
|
||||||
No root access, ADK, or special kernel drivers are required; all drivers are implemented in
|
Android, using the
|
||||||
Java. You get a raw serial port with `read()`, `write()`, and other basic
|
[Android USB Host Mode (OTG)](http://developer.android.com/guide/topics/connectivity/usb/host.html)
|
||||||
functions for use with your own protocols.
|
available since Android 3.1 and working reliably since Android 4.2.
|
||||||
|
|
||||||
* **Homepage**: https://github.com/mik3y/usb-serial-for-android
|
No root access, ADK, or special kernel drivers are required; all drivers are implemented in
|
||||||
* **Google group**: http://groups.google.com/group/usb-serial-for-android
|
Java. You get a raw serial port with `read()`, `write()`, and other basic
|
||||||
* **Latest release**: [v0.1.0](https://github.com/mik3y/usb-serial-for-android/releases)
|
functions for use with your own protocols.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
**1.** [Link your project](https://github.com/mik3y/usb-serial-for-android/wiki/Building-From-Source) to the library.
|
**1.** Add library to your project:
|
||||||
|
|
||||||
**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.
|
Add jitpack.io repository to your root build.gradle:
|
||||||
|
```gradle
|
||||||
**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).
|
allprojects {
|
||||||
|
repositories {
|
||||||
```xml
|
...
|
||||||
<activity
|
maven { url 'https://jitpack.io' }
|
||||||
android:name="..."
|
}
|
||||||
...>
|
}
|
||||||
<intent-filter>
|
```
|
||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
Add library to dependencies
|
||||||
</intent-filter>
|
```gradle
|
||||||
<meta-data
|
dependencies {
|
||||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
implementation 'com.github.mik3y:usb-serial-for-android:Tag'
|
||||||
android:resource="@xml/device_filter" />
|
}
|
||||||
</activity>
|
```
|
||||||
```
|
|
||||||
|
**2.** If the app should be notified when a device is attached, add
|
||||||
**4.** Use it! Example code snippet:
|
[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`.
|
||||||
```java
|
|
||||||
// Find all available drivers from attached devices.
|
```xml
|
||||||
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
<activity
|
||||||
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
|
android:name="..."
|
||||||
if (availableDrivers.isEmpty()) {
|
...>
|
||||||
return;
|
<intent-filter>
|
||||||
}
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
|
</intent-filter>
|
||||||
// Open a connection to the first available driver.
|
<meta-data
|
||||||
UsbSerialDriver driver = availableDrivers.get(0);
|
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||||
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
|
android:resource="@xml/device_filter" />
|
||||||
if (connection == null) {
|
</activity>
|
||||||
// You probably need to call UsbManager.requestPermission(driver.getDevice(), ..)
|
```
|
||||||
return;
|
|
||||||
}
|
**3.** Use it! Example code snippet:
|
||||||
|
|
||||||
// Read some data! Most have just one port (port 0).
|
```java
|
||||||
UsbSerialPort port = driver.getPorts().get(0);
|
// Find all available drivers from attached devices.
|
||||||
try {
|
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||||
port.open(connection);
|
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
|
||||||
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
if (availableDrivers.isEmpty()) {
|
||||||
|
return;
|
||||||
byte buffer[] = new byte[16];
|
}
|
||||||
int numBytesRead = port.read(buffer, 1000);
|
|
||||||
Log.d(TAG, "Read " + numBytesRead + " bytes.");
|
// Open a connection to the first available driver.
|
||||||
} catch (IOException e) {
|
UsbSerialDriver driver = availableDrivers.get(0);
|
||||||
// Deal with error.
|
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
|
||||||
} finally {
|
if (connection == null) {
|
||||||
port.close();
|
// add UsbManager.requestPermission(driver.getDevice(), ..) handling here
|
||||||
}
|
return;
|
||||||
```
|
}
|
||||||
|
|
||||||
For a more complete example, see the
|
UsbSerialPort port = driver.getPorts().get(0); // Most devices have just one port (port 0)
|
||||||
[UsbSerialExamples project](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
|
port.open(connection);
|
||||||
in git, which is a simple application for reading and showing serial data.
|
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
||||||
|
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
|
||||||
A [simple Arduino application](https://github.com/mik3y/usb-serial-for-android/blob/master/arduino)
|
Executors.newSingleThreadExecutor().submit(usbIoManager);
|
||||||
is also available which can be used for testing.
|
```
|
||||||
|
```java
|
||||||
|
port.write("hello".getBytes(), WRITE_WAIT_MILLIS);
|
||||||
## Probing for Unrecognized Devices
|
```
|
||||||
|
```java
|
||||||
Sometimes you may need to do a little extra work to support devices which
|
@Override
|
||||||
usb-serial-for-android doesn't [yet] know about -- but which you know to be
|
public void onNewData(byte[] data) {
|
||||||
compatible with one of the built-in drivers. This may be the case for a brand
|
runOnUiThread(() -> { textView.append(new String(data)); });
|
||||||
new device or for one using a custom VID/PID pair.
|
}
|
||||||
|
```
|
||||||
UsbSerialProber is a class to help you find and instantiate compatible
|
```java
|
||||||
UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use
|
port.close();
|
||||||
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.
|
|
||||||
|
For a simple example, see
|
||||||
To use your own set of rules, create and use a custom prober:
|
[UsbSerialExamples](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
|
||||||
|
folder in this project.
|
||||||
```java
|
|
||||||
// Probe for our custom CDC devices, which use VID 0x1234
|
For a more complete example, see separate github project
|
||||||
// and PIDS 0x0001 and 0x0002.
|
[SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal).
|
||||||
ProbeTable customTable = new ProbeTable();
|
|
||||||
customTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class);
|
## Probing for Unrecognized Devices
|
||||||
customTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class);
|
|
||||||
|
Sometimes you may need to do a little extra work to support devices which
|
||||||
UsbSerialProber prober = new UsbSerialProber(customTable);
|
usb-serial-for-android doesn't (yet) know about -- but which you know to be
|
||||||
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);
|
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
|
||||||
Of course, nothing requires you to use UsbSerialProber at all: you can
|
UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use
|
||||||
instantiate driver classes directly if you know what you're doing; just supply
|
the default prober returned by ``UsbSerialProber.getDefaultProber()``, which
|
||||||
a compatible UsbDevice.
|
uses the built-in list of well-known VIDs and PIDs that are supported by our
|
||||||
|
drivers.
|
||||||
|
|
||||||
## Compatible Devices
|
To use your own set of rules, create and use a custom prober:
|
||||||
|
|
||||||
* *Serial chips:* FT232R, CDC/ACM (eg Arduino Uno) and possibly others.
|
```java
|
||||||
See [CompatibleSerialDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Serial-Devices).
|
// Probe for our custom CDC devices, which use VID 0x1234
|
||||||
* *Android phones and tablets:* Nexus 7, Motorola Xoom, and many others.
|
// and PIDS 0x0001 and 0x0002.
|
||||||
See [CompatibleAndroidDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Android-Devices).
|
ProbeTable customTable = new ProbeTable();
|
||||||
|
customTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class);
|
||||||
|
customTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class);
|
||||||
## Author, License, and Copyright
|
|
||||||
|
UsbSerialProber prober = new UsbSerialProber(customTable);
|
||||||
usb-serial-for-android is written and maintained by *mike wakerly*.
|
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);
|
||||||
|
// ...
|
||||||
This library is licensed under *LGPL Version 2.1*. Please see LICENSE.txt for the
|
```
|
||||||
complete license.
|
|
||||||
|
Of course, nothing requires you to use UsbSerialProber at all: you can
|
||||||
Copyright 2011-2012, Google Inc. All Rights Reserved.
|
instantiate driver classes directly if you know what you're doing; just supply
|
||||||
|
a compatible UsbDevice.
|
||||||
Portions of this library are based on libftdi
|
|
||||||
(http://www.intra2net.com/en/developer/libftdi). Please see
|
## Compatible Devices
|
||||||
FtdiSerialDriver.java for more information.
|
|
||||||
|
This library supports USB to serial converter chips:
|
||||||
## Help & Discussion
|
* FTDI FT232, FT2232, ...
|
||||||
|
* Prolific PL2303
|
||||||
For common problems, see the
|
* Silabs CP2102, CP2105, ...
|
||||||
[Troubleshooting](https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting)
|
* Qinheng CH340
|
||||||
wiki page.
|
|
||||||
|
and devices implementing the CDC/ACM protocol like
|
||||||
For other help and discussion, please join our Google Group,
|
* Arduino using ATmega32U4
|
||||||
[usb-serial-for-android](https://groups.google.com/forum/?fromgroups#!forum/usb-serial-for-android).
|
* Digispark using V-USB software USB
|
||||||
|
* BBC micro:bit using ARM mbed DAPLink firmware
|
||||||
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).
|
|
||||||
|
## 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).
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
jcenter()
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
jcenter()
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
12
gradle/wrapper/gradle-wrapper.properties
vendored
12
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
#Tue Jun 23 00:11:28 EDT 2015
|
#Sun Oct 06 09:46:24 CEST 2019
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||||
|
126
gradlew
vendored
126
gradlew
vendored
@ -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
|
# Attempt to set APP_HOME
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
PRG="$0"
|
||||||
@ -61,9 +36,49 @@ while [ -h "$PRG" ] ; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
SAVED="`pwd`"
|
SAVED="`pwd`"
|
||||||
cd "`dirname \"$PRG\"`/" >&-
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
APP_HOME="`pwd -P`"
|
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
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
@ -90,7 +105,7 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# 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`
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
if [ $? -eq 0 ] ; then
|
if [ $? -eq 0 ] ; then
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
@ -114,6 +129,7 @@ fi
|
|||||||
if $cygwin ; then
|
if $cygwin ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
@ -154,11 +170,19 @@ if $cygwin ; then
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
# Escape application args
|
||||||
function splitJvmOpts() {
|
save () {
|
||||||
JVM_OPTS=("$@")
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
}
|
}
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
APP_ARGS=$(save "$@")
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
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
30
gradlew.bat
vendored
@ -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
|
@if "%DEBUG%" == "" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@ -8,14 +24,14 @@
|
|||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
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
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
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
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
@ -46,10 +62,9 @@ echo location of your Java installation.
|
|||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
: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 not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
:win9xME_args
|
||||||
@rem Slurp the command line arguments.
|
@rem Slurp the command line arguments.
|
||||||
@ -60,11 +75,6 @@ set _SKIP=2
|
|||||||
if "x%~1" == "x" goto execute
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
set CMD_LINE_ARGS=%*
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
64
test/arduino_leonardo_bridge/arduino_leonardo_bridge.ino
Normal file
64
test/arduino_leonardo_bridge/arduino_leonardo_bridge.ino
Normal 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
42
test/rfc2217_server.diff
Normal 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)
|
@ -1,15 +1,15 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 22
|
compileSdkVersion 28
|
||||||
buildToolsVersion "22.0.1"
|
buildToolsVersion '28.0.3'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 17
|
||||||
targetSdkVersion 22
|
targetSdkVersion 28
|
||||||
|
|
||||||
testApplicationId "com.hoho.android.usbserial.examples"
|
|
||||||
testInstrumentationRunner "android.test.InstrumentationTestRunner"
|
testInstrumentationRunner "android.test.InstrumentationTestRunner"
|
||||||
|
missingDimensionStrategy 'device', 'anyDevice'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -20,5 +20,5 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':usbSerialForAndroid')
|
implementation project(':usbSerialForAndroid')
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="1.0" >
|
android:versionName="1.0" >
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="12" />
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.usb.host" />
|
<uses-feature android:name="android.hardware.usb.host" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
@ -22,7 +22,11 @@
|
|||||||
package com.hoho.android.usbserial.examples;
|
package com.hoho.android.usbserial.examples;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
@ -39,12 +43,12 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
import android.widget.TwoLineListItem;
|
import android.widget.TwoLineListItem;
|
||||||
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
||||||
import com.hoho.android.usbserial.util.HexDump;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -59,12 +63,14 @@ public class DeviceListActivity extends Activity {
|
|||||||
private final String TAG = DeviceListActivity.class.getSimpleName();
|
private final String TAG = DeviceListActivity.class.getSimpleName();
|
||||||
|
|
||||||
private UsbManager mUsbManager;
|
private UsbManager mUsbManager;
|
||||||
|
private UsbSerialPort mSerialPort;
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
private TextView mProgressBarTitle;
|
private TextView mProgressBarTitle;
|
||||||
private ProgressBar mProgressBar;
|
private ProgressBar mProgressBar;
|
||||||
|
|
||||||
private static final int MESSAGE_REFRESH = 101;
|
private static final int MESSAGE_REFRESH = 101;
|
||||||
private static final long REFRESH_TIMEOUT_MILLIS = 5000;
|
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() {
|
private final Handler mHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
@ -81,6 +87,7 @@ public class DeviceListActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
private BroadcastReceiver mUsbReceiver;
|
||||||
|
|
||||||
private List<UsbSerialPort> mEntries = new ArrayList<UsbSerialPort>();
|
private List<UsbSerialPort> mEntries = new ArrayList<UsbSerialPort>();
|
||||||
private ArrayAdapter<UsbSerialPort> mAdapter;
|
private ArrayAdapter<UsbSerialPort> mAdapter;
|
||||||
@ -89,11 +96,25 @@ public class DeviceListActivity extends Activity {
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
|
final Context context = this;
|
||||||
|
|
||||||
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||||
mListView = (ListView) findViewById(R.id.deviceList);
|
mListView = findViewById(R.id.deviceList);
|
||||||
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
|
mProgressBar = findViewById(R.id.progressBar);
|
||||||
mProgressBarTitle = (TextView) findViewById(R.id.progressBarTitle);
|
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,
|
mAdapter = new ArrayAdapter<UsbSerialPort>(this,
|
||||||
android.R.layout.simple_expandable_list_item_2, mEntries) {
|
android.R.layout.simple_expandable_list_item_2, mEntries) {
|
||||||
@ -112,9 +133,7 @@ public class DeviceListActivity extends Activity {
|
|||||||
final UsbSerialDriver driver = port.getDriver();
|
final UsbSerialDriver driver = port.getDriver();
|
||||||
final UsbDevice device = driver.getDevice();
|
final UsbDevice device = driver.getDevice();
|
||||||
|
|
||||||
final String title = String.format("Vendor %s Product %s",
|
final String title = String.format("Vendor %4X Product %4X", device.getVendorId(), device.getProductId());
|
||||||
HexDump.toHexString((short) device.getVendorId()),
|
|
||||||
HexDump.toHexString((short) device.getProductId()));
|
|
||||||
row.getText1().setText(title);
|
row.getText1().setText(title);
|
||||||
|
|
||||||
final String subtitle = driver.getClass().getSimpleName();
|
final String subtitle = driver.getClass().getSimpleName();
|
||||||
@ -135,8 +154,14 @@ public class DeviceListActivity extends Activity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final UsbSerialPort port = mEntries.get(position);
|
mSerialPort = mEntries.get(position);
|
||||||
showConsoleActivity(port);
|
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() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mHandler.sendEmptyMessage(MESSAGE_REFRESH);
|
mHandler.sendEmptyMessage(MESSAGE_REFRESH);
|
||||||
|
registerReceiver(mUsbReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
mHandler.removeMessages(MESSAGE_REFRESH);
|
mHandler.removeMessages(MESSAGE_REFRESH);
|
||||||
|
unregisterReceiver(mUsbReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshDeviceList() {
|
private void refreshDeviceList() {
|
@ -1,14 +1,17 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'maven'
|
|
||||||
apply plugin: 'signing'
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 19
|
compileSdkVersion 28
|
||||||
buildToolsVersion "19.1"
|
buildToolsVersion '28.0.3'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 12
|
minSdkVersion 17
|
||||||
targetSdkVersion 19
|
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 {
|
buildTypes {
|
||||||
@ -19,81 +22,14 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.hoho.android"
|
dependencies {
|
||||||
version = "0.2.0-SNAPSHOT"
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'com.android.support:support-annotations:28.0.0'
|
||||||
configurations {
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
archives {
|
androidTestImplementation 'commons-net:commons-net:3.6'
|
||||||
extendsFrom configurations.default
|
androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1'
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signing {
|
//apply from: 'publishToMavenLocal.gradle'
|
||||||
required { has("release") && gradle.taskGraph.hasTask("uploadArchives") }
|
|
||||||
sign configurations.archives
|
|
||||||
}
|
|
||||||
|
|
||||||
def getRepositoryUsername() {
|
//apply from: 'coverage.gradle'
|
||||||
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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
45
usbSerialForAndroid/coverage.gradle
Normal file
45
usbSerialForAndroid/coverage.gradle
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
usbSerialForAndroid/publishToMavenLocal.gradle
Normal file
20
usbSerialForAndroid/publishToMavenLocal.gradle
Normal 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
|
||||||
|
}
|
7
usbSerialForAndroid/src/androidTest/AndroidManifest.xml
Normal file
7
usbSerialForAndroid/src/androidTest/AndroidManifest.xml
Normal 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>
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.hoho.android.usbserial"
|
package="com.hoho.android.usbserial">
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0">
|
|
||||||
<uses-sdk android:minSdkVersion="12" />
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -27,7 +27,6 @@ import android.hardware.usb.UsbDeviceConnection;
|
|||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
import android.hardware.usb.UsbRequest;
|
import android.hardware.usb.UsbRequest;
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -51,6 +50,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
private final UsbSerialPort mPort;
|
||||||
|
private UsbRequest mUsbRequest;
|
||||||
|
|
||||||
public CdcAcmSerialDriver(UsbDevice device) {
|
public CdcAcmSerialDriver(UsbDevice device) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
@ -69,7 +69,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
class CdcAcmSerialPort extends CommonUsbSerialPort {
|
class CdcAcmSerialPort extends CommonUsbSerialPort {
|
||||||
|
|
||||||
private final boolean mEnableAsyncReads;
|
|
||||||
private UsbInterface mControlInterface;
|
private UsbInterface mControlInterface;
|
||||||
private UsbInterface mDataInterface;
|
private UsbInterface mDataInterface;
|
||||||
|
|
||||||
@ -77,6 +76,8 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
private UsbEndpoint mReadEndpoint;
|
private UsbEndpoint mReadEndpoint;
|
||||||
private UsbEndpoint mWriteEndpoint;
|
private UsbEndpoint mWriteEndpoint;
|
||||||
|
|
||||||
|
private int mControlIndex;
|
||||||
|
|
||||||
private boolean mRts = false;
|
private boolean mRts = false;
|
||||||
private boolean mDtr = false;
|
private boolean mDtr = false;
|
||||||
|
|
||||||
@ -90,7 +91,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
public CdcAcmSerialPort(UsbDevice device, int portNumber) {
|
public CdcAcmSerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -116,13 +116,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
openInterface();
|
openInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEnableAsyncReads) {
|
|
||||||
Log.d(TAG, "Async reads enabled");
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Async reads disabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
opened = true;
|
opened = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!opened) {
|
if (!opened) {
|
||||||
@ -139,6 +132,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
// the following code is inspired by the cdc-acm driver
|
// the following code is inspired by the cdc-acm driver
|
||||||
// in the linux kernel
|
// in the linux kernel
|
||||||
|
|
||||||
|
mControlIndex = 0;
|
||||||
mControlInterface = mDevice.getInterface(0);
|
mControlInterface = mDevice.getInterface(0);
|
||||||
Log.d(TAG, "Control iface=" + mControlInterface);
|
Log.d(TAG, "Control iface=" + mControlInterface);
|
||||||
|
|
||||||
@ -196,34 +190,63 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
private void openInterface() throws IOException {
|
private void openInterface() throws IOException {
|
||||||
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
|
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);
|
Log.d(TAG, "Control iface=" + mControlInterface);
|
||||||
// class should be USB_CLASS_COMM
|
|
||||||
|
|
||||||
if (!mConnection.claimInterface(mControlInterface, true)) {
|
if (!mConnection.claimInterface(mControlInterface, true)) {
|
||||||
throw new IOException("Could not claim control interface.");
|
throw new IOException("Could not claim control interface.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mControlEndpoint = mControlInterface.getEndpoint(0);
|
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.");
|
if(mDataInterface == null) {
|
||||||
mDataInterface = mDevice.getInterface(1);
|
throw new IOException("no data interface.");
|
||||||
|
}
|
||||||
Log.d(TAG, "data iface=" + mDataInterface);
|
Log.d(TAG, "data iface=" + mDataInterface);
|
||||||
// class should be USB_CLASS_CDC_DATA
|
|
||||||
|
|
||||||
if (!mConnection.claimInterface(mDataInterface, true)) {
|
if (!mConnection.claimInterface(mDataInterface, true)) {
|
||||||
throw new IOException("Could not claim data interface.");
|
throw new IOException("Could not claim data interface.");
|
||||||
}
|
}
|
||||||
mReadEndpoint = mDataInterface.getEndpoint(1);
|
|
||||||
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
|
mReadEndpoint = null;
|
||||||
mWriteEndpoint = mDataInterface.getEndpoint(0);
|
mWriteEndpoint = null;
|
||||||
Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
|
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) {
|
private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException {
|
||||||
return mConnection.controlTransfer(
|
int len = mConnection.controlTransfer(
|
||||||
USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
|
USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000);
|
||||||
|
if(len < 0) {
|
||||||
|
throw new IOException("controlTransfer failed.");
|
||||||
|
}
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -231,57 +254,43 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
if (mConnection == null) {
|
if (mConnection == null) {
|
||||||
throw new IOException("Already closed");
|
throw new IOException("Already closed");
|
||||||
}
|
}
|
||||||
|
synchronized (this) {
|
||||||
|
if (mUsbRequest != null)
|
||||||
|
mUsbRequest.cancel();
|
||||||
|
}
|
||||||
mConnection.close();
|
mConnection.close();
|
||||||
mConnection = null;
|
mConnection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||||
if (mEnableAsyncReads) {
|
final UsbRequest request = new UsbRequest();
|
||||||
final UsbRequest request = new UsbRequest();
|
try {
|
||||||
try {
|
|
||||||
request.initialize(mConnection, mReadEndpoint);
|
request.initialize(mConnection, mReadEndpoint);
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
if (!request.queue(buf, dest.length)) {
|
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();
|
final UsbRequest response = mConnection.requestWait();
|
||||||
|
synchronized (this) {
|
||||||
|
mUsbRequest = null;
|
||||||
|
}
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw new IOException("Null response");
|
throw new IOException("Null response");
|
||||||
}
|
}
|
||||||
|
|
||||||
final int nread = buf.position();
|
final int nread = buf.position();
|
||||||
if (nread > 0) {
|
if (nread > 0) {
|
||||||
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
|
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
|
||||||
return nread;
|
return nread;
|
||||||
} else {
|
} 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;
|
return 0;
|
||||||
}
|
}
|
||||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
} finally {
|
||||||
|
mUsbRequest = null;
|
||||||
|
request.close();
|
||||||
}
|
}
|
||||||
return numBytesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -320,7 +329,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
byte stopBitsByte;
|
||||||
switch (stopBits) {
|
switch (stopBits) {
|
||||||
case STOPBITS_1: stopBitsByte = 0; break;
|
case STOPBITS_1: stopBitsByte = 0; break;
|
||||||
@ -392,7 +401,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
setDtrRts();
|
setDtrRts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDtrRts() {
|
private void setDtrRts() throws IOException {
|
||||||
int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
|
int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
|
||||||
sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
|
sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
|
||||||
}
|
}
|
||||||
@ -401,7 +410,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
||||||
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),
|
supportedDevices.put(UsbId.VENDOR_ARDUINO,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.ARDUINO_UNO,
|
UsbId.ARDUINO_UNO,
|
||||||
UsbId.ARDUINO_UNO_R3,
|
UsbId.ARDUINO_UNO_R3,
|
||||||
@ -414,18 +423,22 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||||||
UsbId.ARDUINO_LEONARDO,
|
UsbId.ARDUINO_LEONARDO,
|
||||||
UsbId.ARDUINO_MICRO,
|
UsbId.ARDUINO_MICRO,
|
||||||
});
|
});
|
||||||
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),
|
supportedDevices.put(UsbId.VENDOR_VAN_OOIJEN_TECH,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
|
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
|
||||||
});
|
});
|
||||||
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL),
|
supportedDevices.put(UsbId.VENDOR_ATMEL,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
|
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
|
||||||
});
|
});
|
||||||
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS),
|
supportedDevices.put(UsbId.VENDOR_LEAFLABS,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.LEAFLABS_MAPLE,
|
UsbId.LEAFLABS_MAPLE,
|
||||||
});
|
});
|
||||||
|
supportedDevices.put(UsbId.VENDOR_ARM,
|
||||||
|
new int[] {
|
||||||
|
UsbId.ARM_MBED,
|
||||||
|
});
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,11 @@ import android.hardware.usb.UsbDevice;
|
|||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
|
import android.hardware.usb.UsbRequest;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -46,6 +48,17 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
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) {
|
public Ch34xSerialDriver(UsbDevice device) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mPort = new Ch340SerialPort(mDevice, 0);
|
mPort = new Ch340SerialPort(mDevice, 0);
|
||||||
@ -72,6 +85,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
private UsbEndpoint mReadEndpoint;
|
private UsbEndpoint mReadEndpoint;
|
||||||
private UsbEndpoint mWriteEndpoint;
|
private UsbEndpoint mWriteEndpoint;
|
||||||
|
private UsbRequest mUsbRequest;
|
||||||
|
|
||||||
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
@ -93,10 +107,8 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
try {
|
try {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||||
UsbInterface usbIface = mDevice.getInterface(i);
|
UsbInterface usbIface = mDevice.getInterface(i);
|
||||||
if (mConnection.claimInterface(usbIface, true)) {
|
if (!mConnection.claimInterface(usbIface, true)) {
|
||||||
Log.d(TAG, "claimInterface " + i + " SUCCESS");
|
throw new IOException("Could not claim data interface.");
|
||||||
} else {
|
|
||||||
Log.d(TAG, "claimInterface " + i + " FAIL");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +124,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
setBaudRate(DEFAULT_BAUD_RATE);
|
setBaudRate(DEFAULT_BAUD_RATE);
|
||||||
|
|
||||||
@ -133,9 +144,10 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
if (mConnection == null) {
|
if (mConnection == null) {
|
||||||
throw new IOException("Already closed");
|
throw new IOException("Already closed");
|
||||||
}
|
}
|
||||||
|
synchronized (this) {
|
||||||
// TODO: nothing sended on close, maybe needed?
|
if (mUsbRequest != null)
|
||||||
|
mUsbRequest.cancel();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
mConnection.close();
|
mConnection.close();
|
||||||
} finally {
|
} finally {
|
||||||
@ -146,21 +158,33 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||||
final int numBytesRead;
|
final UsbRequest request = new UsbRequest();
|
||||||
synchronized (mReadBufferLock) {
|
try {
|
||||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
request.initialize(mConnection, mReadEndpoint);
|
||||||
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
timeoutMillis);
|
if (!request.queue(buf, dest.length)) {
|
||||||
if (numBytesRead < 0) {
|
throw new IOException("Error queueing request.");
|
||||||
// This sucks: we get -1 on timeout, not 0 as preferred.
|
}
|
||||||
// We *should* use UsbRequest, except it has a bug/api oversight
|
mUsbRequest = request;
|
||||||
// where there is no way to determine the number of bytes read
|
final UsbRequest response = mConnection.requestWait();
|
||||||
// in response :\ -- http://b.android.com/28023
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
} finally {
|
||||||
|
mUsbRequest = null;
|
||||||
|
request.close();
|
||||||
}
|
}
|
||||||
return numBytesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -252,7 +276,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
|
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");
|
throw new IOException("init failed! #5");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,36 +295,93 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
|
|
||||||
private void setBaudRate(int baudRate) throws IOException {
|
private void setBaudRate(int baudRate) throws IOException {
|
||||||
int[] baud = new int[]{2400, 0xd901, 0x0038, 4800, 0x6402,
|
final long CH341_BAUDBASE_FACTOR = 1532620800;
|
||||||
0x001f, 9600, 0xb202, 0x0013, 19200, 0xd902, 0x000d, 38400,
|
final int CH341_BAUDBASE_DIVMAX = 3;
|
||||||
0x6403, 0x000a, 115200, 0xcc03, 0x0008};
|
|
||||||
|
|
||||||
for (int i = 0; i < baud.length / 3; i++) {
|
long factor = CH341_BAUDBASE_FACTOR / baudRate;
|
||||||
if (baud[i * 3] == baudRate) {
|
int divisor = CH341_BAUDBASE_DIVMAX;
|
||||||
int ret = controlOut(0x9a, 0x1312, baud[i * 3 + 1]);
|
|
||||||
if (ret < 0) {
|
while ((factor > 0xfff0) && divisor > 0) {
|
||||||
throw new IOException("Error setting baud rate. #1");
|
factor >>= 3;
|
||||||
}
|
divisor--;
|
||||||
ret = controlOut(0x9a, 0x0f2c, baud[i * 3 + 2]);
|
|
||||||
if (ret < 0) {
|
|
||||||
throw new IOException("Error setting baud rate. #1");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@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 {
|
throws IOException {
|
||||||
setBaudRate(baudRate);
|
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
|
@Override
|
||||||
@ -345,11 +426,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||||||
writeHandshakeByte();
|
writeHandshakeByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
|
@ -160,8 +160,8 @@ abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
public abstract void setRTS(boolean value) throws IOException;
|
public abstract void setRTS(boolean value) throws IOException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException {
|
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
return !flushReadBuffers && !flushWriteBuffers;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,12 @@ import android.hardware.usb.UsbDevice;
|
|||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
|
import android.hardware.usb.UsbRequest;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -39,11 +41,14 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
|
private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
|
||||||
|
|
||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
private final List<UsbSerialPort> mPorts;
|
||||||
|
|
||||||
public Cp21xxSerialDriver(UsbDevice device) {
|
public Cp21xxSerialDriver(UsbDevice device) {
|
||||||
mDevice = 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
|
@Override
|
||||||
@ -53,7 +58,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UsbSerialPort> getPorts() {
|
public List<UsbSerialPort> getPorts() {
|
||||||
return Collections.singletonList(mPort);
|
return mPorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Cp21xxSerialPort extends CommonUsbSerialPort {
|
public class Cp21xxSerialPort extends CommonUsbSerialPort {
|
||||||
@ -103,6 +108,11 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
private UsbEndpoint mReadEndpoint;
|
private UsbEndpoint mReadEndpoint;
|
||||||
private UsbEndpoint mWriteEndpoint;
|
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) {
|
public Cp21xxSerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
@ -115,7 +125,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
private int setConfigSingle(int request, int value) {
|
private int setConfigSingle(int request, int value) {
|
||||||
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, 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
|
@Override
|
||||||
@ -126,17 +136,15 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
mConnection = connection;
|
mConnection = connection;
|
||||||
boolean opened = false;
|
boolean opened = false;
|
||||||
|
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
if(mPortNumber >= mDevice.getInterfaceCount()) {
|
||||||
UsbInterface usbIface = mDevice.getInterface(i);
|
throw new IOException("Unknown port number");
|
||||||
if (mConnection.claimInterface(usbIface, true)) {
|
}
|
||||||
Log.d(TAG, "claimInterface " + i + " SUCCESS");
|
UsbInterface dataIface = mDevice.getInterface(mPortNumber);
|
||||||
} else {
|
if (!mConnection.claimInterface(dataIface, true)) {
|
||||||
Log.d(TAG, "claimInterface " + i + " FAIL");
|
throw new IOException("Could not claim interface " + mPortNumber);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
|
||||||
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
||||||
UsbEndpoint ep = dataIface.getEndpoint(i);
|
UsbEndpoint ep = dataIface.getEndpoint(i);
|
||||||
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||||
@ -169,8 +177,16 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
if (mConnection == null) {
|
if (mConnection == null) {
|
||||||
throw new IOException("Already closed");
|
throw new IOException("Already closed");
|
||||||
}
|
}
|
||||||
|
synchronized (this) {
|
||||||
|
if(mUsbRequest != null) {
|
||||||
|
mUsbRequest.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
|
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
|
||||||
|
} catch (Exception ignored)
|
||||||
|
{}
|
||||||
|
try {
|
||||||
mConnection.close();
|
mConnection.close();
|
||||||
} finally {
|
} finally {
|
||||||
mConnection = null;
|
mConnection = null;
|
||||||
@ -179,21 +195,33 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||||
final int numBytesRead;
|
final UsbRequest request = new UsbRequest();
|
||||||
synchronized (mReadBufferLock) {
|
try {
|
||||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
request.initialize(mConnection, mReadEndpoint);
|
||||||
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
timeoutMillis);
|
if (!request.queue(buf, dest.length)) {
|
||||||
if (numBytesRead < 0) {
|
throw new IOException("Error queueing request.");
|
||||||
// This sucks: we get -1 on timeout, not 0 as preferred.
|
}
|
||||||
// We *should* use UsbRequest, except it has a bug/api oversight
|
mUsbRequest = request;
|
||||||
// where there is no way to determine the number of bytes read
|
final UsbRequest response = mConnection.requestWait();
|
||||||
// in response :\ -- http://b.android.com/28023
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
} finally {
|
||||||
|
mUsbRequest = null;
|
||||||
|
request.close();
|
||||||
}
|
}
|
||||||
return numBytesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -238,7 +266,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
(byte) ((baudRate >> 24) & 0xff)
|
(byte) ((baudRate >> 24) & 0xff)
|
||||||
};
|
};
|
||||||
int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
|
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) {
|
if (ret < 0) {
|
||||||
throw new IOException("Error setting baud rate.");
|
throw new IOException("Error setting baud rate.");
|
||||||
}
|
}
|
||||||
@ -252,38 +280,62 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
int configDataBits = 0;
|
int configDataBits = 0;
|
||||||
switch (dataBits) {
|
switch (dataBits) {
|
||||||
case DATABITS_5:
|
case DATABITS_5:
|
||||||
|
if(mIsRestrictedPort)
|
||||||
|
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
|
||||||
configDataBits |= 0x0500;
|
configDataBits |= 0x0500;
|
||||||
break;
|
break;
|
||||||
case DATABITS_6:
|
case DATABITS_6:
|
||||||
|
if(mIsRestrictedPort)
|
||||||
|
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
|
||||||
configDataBits |= 0x0600;
|
configDataBits |= 0x0600;
|
||||||
break;
|
break;
|
||||||
case DATABITS_7:
|
case DATABITS_7:
|
||||||
|
if(mIsRestrictedPort)
|
||||||
|
throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits);
|
||||||
configDataBits |= 0x0700;
|
configDataBits |= 0x0700;
|
||||||
break;
|
break;
|
||||||
case DATABITS_8:
|
case DATABITS_8:
|
||||||
configDataBits |= 0x0800;
|
configDataBits |= 0x0800;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
configDataBits |= 0x0800;
|
throw new IllegalArgumentException("Unknown dataBits value: " + dataBits);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parity) {
|
switch (parity) {
|
||||||
|
case PARITY_NONE:
|
||||||
|
break;
|
||||||
case PARITY_ODD:
|
case PARITY_ODD:
|
||||||
configDataBits |= 0x0010;
|
configDataBits |= 0x0010;
|
||||||
break;
|
break;
|
||||||
case PARITY_EVEN:
|
case PARITY_EVEN:
|
||||||
configDataBits |= 0x0020;
|
configDataBits |= 0x0020;
|
||||||
break;
|
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) {
|
switch (stopBits) {
|
||||||
case STOPBITS_1:
|
case STOPBITS_1:
|
||||||
configDataBits |= 0;
|
|
||||||
break;
|
break;
|
||||||
|
case STOPBITS_1_5:
|
||||||
|
throw new IllegalArgumentException("Unsupported stopBits value: 1.5");
|
||||||
case STOPBITS_2:
|
case STOPBITS_2:
|
||||||
|
if(mIsRestrictedPort)
|
||||||
|
throw new IllegalArgumentException("Unsupported stopBits value: 2");
|
||||||
configDataBits |= 2;
|
configDataBits |= 2;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
|
||||||
}
|
}
|
||||||
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
|
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
|
||||||
}
|
}
|
||||||
@ -327,8 +379,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean purgeHwBuffers(boolean purgeReadBuffers,
|
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
boolean purgeWriteBuffers) throws IOException {
|
|
||||||
int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
|
int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
|
||||||
| (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
|
| (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
|
||||||
|
|
||||||
@ -343,7 +394,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
||||||
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS),
|
supportedDevices.put(UsbId.VENDOR_SILABS,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.SILABS_CP2102,
|
UsbId.SILABS_CP2102,
|
||||||
UsbId.SILABS_CP2105,
|
UsbId.SILABS_CP2105,
|
||||||
|
@ -28,11 +28,9 @@ import android.hardware.usb.UsbEndpoint;
|
|||||||
import android.hardware.usb.UsbRequest;
|
import android.hardware.usb.UsbRequest;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.hoho.android.usbserial.util.HexDump;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collections;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -72,6 +70,8 @@ import java.util.Map;
|
|||||||
* Supported and tested devices:
|
* Supported and tested devices:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@value DeviceType#TYPE_R}</li>
|
* <li>{@value DeviceType#TYPE_R}</li>
|
||||||
|
* <li>{@value DeviceType#TYPE_2232H}</li>
|
||||||
|
* <li>{@value DeviceType#TYPE_4232H}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
@ -79,8 +79,6 @@ import java.util.Map;
|
|||||||
* feedback or patches):
|
* feedback or patches):
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@value DeviceType#TYPE_2232C}</li>
|
* <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_AM}</li>
|
||||||
* <li>{@value DeviceType#TYPE_BM}</li>
|
* <li>{@value DeviceType#TYPE_BM}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
@ -95,7 +93,7 @@ import java.util.Map;
|
|||||||
public class FtdiSerialDriver implements UsbSerialDriver {
|
public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
private final List<UsbSerialPort> mPorts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FTDI chip types.
|
* FTDI chip types.
|
||||||
@ -106,8 +104,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
public FtdiSerialDriver(UsbDevice device) {
|
public FtdiSerialDriver(UsbDevice device) {
|
||||||
mDevice = 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
|
@Override
|
||||||
public UsbDevice getDevice() {
|
public UsbDevice getDevice() {
|
||||||
return mDevice;
|
return mDevice;
|
||||||
@ -115,7 +117,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UsbSerialPort> getPorts() {
|
public List<UsbSerialPort> getPorts() {
|
||||||
return Collections.singletonList(mPort);
|
return mPorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FtdiSerialPort extends CommonUsbSerialPort {
|
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_SET_DATA_REQUEST = 4;
|
||||||
|
|
||||||
private static final int SIO_RESET_SIO = 0;
|
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;
|
private static final int SIO_RESET_PURGE_TX = 2;
|
||||||
|
|
||||||
public static final int FTDI_DEVICE_OUT_REQTYPE =
|
public static final int FTDI_DEVICE_OUT_REQTYPE =
|
||||||
@ -181,16 +183,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
private DeviceType mType;
|
private DeviceType mType;
|
||||||
|
|
||||||
private int mInterface = 0; /* INTERFACE_ANY */
|
private int mIndex = 0;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public FtdiSerialPort(UsbDevice device, int portNumber) {
|
public FtdiSerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
@ -210,10 +203,10 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
* @return The number of payload bytes
|
* @return The number of payload bytes
|
||||||
*/
|
*/
|
||||||
private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) {
|
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) {
|
for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) {
|
||||||
final int count = (packetIdx == (packetsCount - 1))
|
final int count = (packetIdx == (packetsCount - 1))
|
||||||
? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH
|
? totalBytesRead - packetIdx * maxPacketSize - MODEM_STATUS_HEADER_LENGTH
|
||||||
: maxPacketSize - MODEM_STATUS_HEADER_LENGTH;
|
: maxPacketSize - MODEM_STATUS_HEADER_LENGTH;
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
System.arraycopy(src,
|
System.arraycopy(src,
|
||||||
@ -228,14 +221,21 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reset() throws IOException {
|
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,
|
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) {
|
if (result != 0) {
|
||||||
throw new IOException("Reset failed: result=" + result);
|
throw new IOException("Reset failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(mikey): autodetect.
|
|
||||||
mType = DeviceType.TYPE_R;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -247,12 +247,10 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
boolean opened = false;
|
boolean opened = false;
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
if (connection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
||||||
if (connection.claimInterface(mDevice.getInterface(i), true)) {
|
Log.d(TAG, "claimInterface " + mPortNumber + " SUCCESS");
|
||||||
Log.d(TAG, "claimInterface " + i + " SUCCESS");
|
} else {
|
||||||
} else {
|
throw new IOException("Error claiming interface " + mPortNumber);
|
||||||
throw new IOException("Error claiming interface " + i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
reset();
|
reset();
|
||||||
opened = true;
|
opened = true;
|
||||||
@ -278,20 +276,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||||
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
|
final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(0);
|
||||||
|
final UsbRequest request = new UsbRequest();
|
||||||
if (ENABLE_ASYNC_READS) {
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
final int readAmt;
|
try {
|
||||||
synchronized (mReadBufferLock) {
|
|
||||||
// mReadBuffer is only used for maximum read size.
|
|
||||||
readAmt = Math.min(dest.length, mReadBuffer.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
final UsbRequest request = new UsbRequest();
|
|
||||||
request.initialize(mConnection, endpoint);
|
request.initialize(mConnection, endpoint);
|
||||||
|
if (!request.queue(buf, dest.length)) {
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
|
||||||
if (!request.queue(buf, readAmt)) {
|
|
||||||
throw new IOException("Error queueing request.");
|
throw new IOException("Error queueing request.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,34 +289,21 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw new IOException("Null response");
|
throw new IOException("Null response");
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
|
request.close();
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public int write(byte[] src, int timeoutMillis) throws IOException {
|
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;
|
int offset = 0;
|
||||||
|
|
||||||
while (offset < src.length) {
|
while (offset < src.length) {
|
||||||
@ -379,7 +356,18 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
setBaudRate(baudRate);
|
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) {
|
switch (parity) {
|
||||||
case PARITY_NONE:
|
case PARITY_NONE:
|
||||||
@ -406,8 +394,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
config |= (0x00 << 11);
|
config |= (0x00 << 11);
|
||||||
break;
|
break;
|
||||||
case STOPBITS_1_5:
|
case STOPBITS_1_5:
|
||||||
config |= (0x01 << 11);
|
throw new IllegalArgumentException("Unsupported stopBits value: 1.5");
|
||||||
break;
|
|
||||||
case STOPBITS_2:
|
case STOPBITS_2:
|
||||||
config |= (0x02 << 11);
|
config |= (0x02 << 11);
|
||||||
break;
|
break;
|
||||||
@ -416,7 +403,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
|
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);
|
null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
throw new IOException("Setting parameters failed: result=" + result);
|
throw new IOException("Setting parameters failed: result=" + result);
|
||||||
@ -496,9 +483,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
long index;
|
long index;
|
||||||
if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
|
if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
|
||||||
|| mType == DeviceType.TYPE_4232H) {
|
|| mType == DeviceType.TYPE_4232H) {
|
||||||
index = (encodedDivisor >> 8) & 0xffff;
|
index = (encodedDivisor >> 8) & 0xff00;
|
||||||
index &= 0xFF00;
|
index |= mIndex;
|
||||||
index |= 0 /* TODO mIndex */;
|
|
||||||
} else {
|
} else {
|
||||||
index = (encodedDivisor >> 16) & 0xffff;
|
index = (encodedDivisor >> 16) & 0xffff;
|
||||||
}
|
}
|
||||||
@ -548,20 +534,20 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
|
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
if (purgeReadBuffers) {
|
if (purgeWriteBuffers) {
|
||||||
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
|
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) {
|
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,
|
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) {
|
if (result != 0) {
|
||||||
throw new IOException("Flushing RX failed: result=" + result);
|
throw new IOException("purge read buffer failed: result=" + result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -570,9 +556,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
||||||
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
|
supportedDevices.put(UsbId.VENDOR_FTDI,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.FTDI_FT232R,
|
UsbId.FTDI_FT232R,
|
||||||
|
UsbId.FTDI_FT232H,
|
||||||
|
UsbId.FTDI_FT2232H,
|
||||||
|
UsbId.FTDI_FT4232H,
|
||||||
UsbId.FTDI_FT231X,
|
UsbId.FTDI_FT231X,
|
||||||
});
|
});
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
|
@ -32,10 +32,12 @@ import android.hardware.usb.UsbDevice;
|
|||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
|
import android.hardware.usb.UsbRequest;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -86,7 +88,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||||||
private static final int READ_ENDPOINT = 0x83;
|
private static final int READ_ENDPOINT = 0x83;
|
||||||
private static final int INTERRUPT_ENDPOINT = 0x81;
|
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 FLUSH_TX_REQUEST = 0x09;
|
||||||
|
|
||||||
private static final int SET_LINE_REQUEST = 0x20;
|
private static final int SET_LINE_REQUEST = 0x20;
|
||||||
@ -368,15 +370,28 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||||
synchronized (mReadBufferLock) {
|
final UsbRequest request = new UsbRequest();
|
||||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
try {
|
||||||
int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,
|
request.initialize(mConnection, mReadEndpoint);
|
||||||
readAmt, timeoutMillis);
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
if (numBytesRead < 0) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
} finally {
|
||||||
return numBytesRead;
|
request.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,22 +553,22 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
|
public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
if (purgeReadBuffers) {
|
if (purgeWriteBuffers) {
|
||||||
vendorOut(FLUSH_RX_REQUEST, 0, null);
|
vendorOut(FLUSH_RX_REQUEST, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (purgeWriteBuffers) {
|
if (purgeReadBuffers) {
|
||||||
vendorOut(FLUSH_TX_REQUEST, 0, null);
|
vendorOut(FLUSH_TX_REQUEST, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return purgeReadBuffers || purgeWriteBuffers;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
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, });
|
new int[] { UsbId.PROLIFIC_PL2303, });
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ public final class UsbId {
|
|||||||
|
|
||||||
public static final int VENDOR_FTDI = 0x0403;
|
public static final int VENDOR_FTDI = 0x0403;
|
||||||
public static final int FTDI_FT232R = 0x6001;
|
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 FTDI_FT231X = 0x6015;
|
||||||
|
|
||||||
public static final int VENDOR_ATMEL = 0x03EB;
|
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 VENDOR_QINHENG = 0x1a86;
|
||||||
public static final int QINHENG_HL340 = 0x7523;
|
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() {
|
private UsbId() {
|
||||||
throw new IllegalAccessError("Non-instantiable class.");
|
throw new IllegalAccessError("Non-instantiable class.");
|
||||||
}
|
}
|
||||||
|
@ -216,13 +216,13 @@ public interface UsbSerialPort {
|
|||||||
public void setRTS(boolean value) throws IOException;
|
public void setRTS(boolean value) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush non-transmitted output data and / or non-read input data
|
* purge non-transmitted output data and / or non-read input data
|
||||||
* @param flushRX {@code true} to flush non-transmitted output data
|
* @param purgeWriteBuffers {@code true} to discard non-transmitted output data
|
||||||
* @param flushTX {@code true} to flush non-read input data
|
* @param purgeReadBuffers {@code true} to discard non-read input data
|
||||||
* @return {@code true} if the operation was successful, or
|
* @return {@code true} if the operation was successful, or
|
||||||
* {@code false} if the operation is not supported by the driver or device
|
* {@code false} if the operation is not supported by the driver or device
|
||||||
* @throws IOException if an error occurred during flush
|
* @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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -50,7 +50,7 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
// Synchronized by 'mWriteBuffer'
|
// Synchronized by 'mWriteBuffer'
|
||||||
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
||||||
|
|
||||||
private enum State {
|
public enum State {
|
||||||
STOPPED,
|
STOPPED,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
STOPPING
|
STOPPING
|
||||||
@ -111,7 +111,7 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized State getState() {
|
public synchronized State getState() {
|
||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,6 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
* called, or until a driver exception is raised.
|
* called, or until a driver exception is raised.
|
||||||
*
|
*
|
||||||
* NOTE(mikey): Uses inefficient read/write-with-timeout.
|
* NOTE(mikey): Uses inefficient read/write-with-timeout.
|
||||||
* TODO(mikey): Read asynchronously with {@link UsbRequest#queue(ByteBuffer, int)}
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user