From 8abc3be1f1485ecaf9696a9c470620b066d52a1f Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Mon, 28 Oct 2013 16:11:21 -0700
Subject: [PATCH 01/12] API refactor, adding UsbSerialPort interface.
- UsbSerialDriver is now a discrete interface.
- UsbSerialDriver provides getPorts() method, returning one or
more usable UsbSerialPort.
- Use of UsbDeviceConnection is deferred until open(),
making it possible to probe for ports without
permission from Android.
(Thanks to Felix for inspiring some of these changes).
---
.../examples/DeviceListActivity.java | 81 +-
.../examples/SerialConsoleActivity.java | 51 +-
.../usbserial/driver/CdcAcmSerialDriver.java | 381 ++++----
...alDriver.java => CommonUsbSerialPort.java} | 16 +-
.../usbserial/driver/Cp2102SerialDriver.java | 568 ++++++-----
.../usbserial/driver/FtdiSerialDriver.java | 838 +++++++++--------
.../android/usbserial/driver/ProbeTable.java | 108 +++
.../driver/ProlificSerialDriver.java | 886 +++++++++---------
.../hoho/android/usbserial/driver/UsbId.java | 8 +-
.../usbserial/driver/UsbSerialDriver.java | 188 +---
.../usbserial/driver/UsbSerialPort.java | 218 +++++
.../usbserial/driver/UsbSerialProber.java | 253 +----
.../util/SerialInputOutputManager.java | 15 +-
13 files changed, 1910 insertions(+), 1701 deletions(-)
rename UsbSerialLibrary/src/com/hoho/android/usbserial/driver/{CommonUsbSerialDriver.java => CommonUsbSerialPort.java} (90%)
create mode 100644 UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProbeTable.java
create mode 100644 UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java
diff --git a/UsbSerialExamples/src/com/hoho/android/usbserial/examples/DeviceListActivity.java b/UsbSerialExamples/src/com/hoho/android/usbserial/examples/DeviceListActivity.java
index fd2429a..c7804e0 100644
--- a/UsbSerialExamples/src/com/hoho/android/usbserial/examples/DeviceListActivity.java
+++ b/UsbSerialExamples/src/com/hoho/android/usbserial/examples/DeviceListActivity.java
@@ -1,4 +1,5 @@
-/* Copyright 2011 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.examples;
@@ -41,6 +42,7 @@ import android.widget.TextView;
import android.widget.TwoLineListItem;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
+import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.HexDump;
@@ -80,19 +82,8 @@ public class DeviceListActivity extends Activity {
};
- /** Simple container for a UsbDevice and its driver. */
- private static class DeviceEntry {
- public UsbDevice device;
- public UsbSerialDriver driver;
-
- DeviceEntry(UsbDevice device, UsbSerialDriver driver) {
- this.device = device;
- this.driver = driver;
- }
- }
-
- private List mEntries = new ArrayList();
- private ArrayAdapter mAdapter;
+ private List mEntries = new ArrayList();
+ private ArrayAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -104,7 +95,8 @@ public class DeviceListActivity extends Activity {
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mProgressBarTitle = (TextView) findViewById(R.id.progressBarTitle);
- mAdapter = new ArrayAdapter(this, android.R.layout.simple_expandable_list_item_2, mEntries) {
+ mAdapter = new ArrayAdapter(this,
+ android.R.layout.simple_expandable_list_item_2, mEntries) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final TwoLineListItem row;
@@ -116,14 +108,16 @@ public class DeviceListActivity extends Activity {
row = (TwoLineListItem) convertView;
}
- final DeviceEntry entry = mEntries.get(position);
+ final UsbSerialPort port = mEntries.get(position);
+ final UsbSerialDriver driver = port.getDriver();
+ final UsbDevice device = driver.getDevice();
+
final String title = String.format("Vendor %s Product %s",
- HexDump.toHexString((short) entry.device.getVendorId()),
- HexDump.toHexString((short) entry.device.getProductId()));
+ HexDump.toHexString((short) device.getVendorId()),
+ HexDump.toHexString((short) device.getProductId()));
row.getText1().setText(title);
- final String subtitle = entry.driver != null ?
- entry.driver.getClass().getSimpleName() : "No Driver";
+ final String subtitle = driver.getClass().getSimpleName();
row.getText2().setText(subtitle);
return row;
@@ -141,14 +135,8 @@ public class DeviceListActivity extends Activity {
return;
}
- final DeviceEntry entry = mEntries.get(position);
- final UsbSerialDriver driver = entry.driver;
- if (driver == null) {
- Log.d(TAG, "No driver.");
- return;
- }
-
- showConsoleActivity(driver);
+ final UsbSerialPort port = mEntries.get(position);
+ showConsoleActivity(port);
}
});
}
@@ -168,31 +156,28 @@ public class DeviceListActivity extends Activity {
private void refreshDeviceList() {
showProgressBar();
- new AsyncTask>() {
+ new AsyncTask>() {
@Override
- protected List doInBackground(Void... params) {
+ protected List doInBackground(Void... params) {
Log.d(TAG, "Refreshing device list ...");
SystemClock.sleep(1000);
- final List result = new ArrayList();
- for (final UsbDevice device : mUsbManager.getDeviceList().values()) {
- final List drivers =
- UsbSerialProber.probeSingleDevice(mUsbManager, device);
- Log.d(TAG, "Found usb device: " + device);
- if (drivers.isEmpty()) {
- Log.d(TAG, " - No UsbSerialDriver available.");
- result.add(new DeviceEntry(device, null));
- } else {
- for (UsbSerialDriver driver : drivers) {
- Log.d(TAG, " + " + driver);
- result.add(new DeviceEntry(device, driver));
- }
- }
+
+ final List drivers =
+ UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager);
+
+ final List result = new ArrayList();
+ for (final UsbSerialDriver driver : drivers) {
+ final List ports = driver.getPorts();
+ Log.d(TAG, String.format("+ %s: %s port%s",
+ driver, Integer.valueOf(ports.size()), ports.size() == 1 ? "" : "s"));
+ result.addAll(ports);
}
+
return result;
}
@Override
- protected void onPostExecute(List result) {
+ protected void onPostExecute(List result) {
mEntries.clear();
mEntries.addAll(result);
mAdapter.notifyDataSetChanged();
@@ -214,8 +199,8 @@ public class DeviceListActivity extends Activity {
mProgressBar.setVisibility(View.INVISIBLE);
}
- private void showConsoleActivity(UsbSerialDriver driver) {
- SerialConsoleActivity.show(this, driver);
+ private void showConsoleActivity(UsbSerialPort port) {
+ SerialConsoleActivity.show(this, port);
}
}
diff --git a/UsbSerialExamples/src/com/hoho/android/usbserial/examples/SerialConsoleActivity.java b/UsbSerialExamples/src/com/hoho/android/usbserial/examples/SerialConsoleActivity.java
index 7ccb406..d30ff51 100644
--- a/UsbSerialExamples/src/com/hoho/android/usbserial/examples/SerialConsoleActivity.java
+++ b/UsbSerialExamples/src/com/hoho/android/usbserial/examples/SerialConsoleActivity.java
@@ -1,4 +1,5 @@
-/* Copyright 2011 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.examples;
@@ -23,12 +24,14 @@ package com.hoho.android.usbserial.examples;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.ScrollView;
import android.widget.TextView;
-import com.hoho.android.usbserial.driver.UsbSerialDriver;
+import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.util.HexDump;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
@@ -37,7 +40,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
- * Monitors a single {@link UsbSerialDriver} instance, showing all data
+ * Monitors a single {@link UsbSerialPort} instance, showing all data
* received.
*
* @author mike wakerly (opensource@hoho.com)
@@ -48,7 +51,7 @@ public class SerialConsoleActivity extends Activity {
/**
* Driver instance, passed in statically via
- * {@link #show(Context, UsbSerialDriver)}.
+ * {@link #show(Context, UsbSerialPort)}.
*
*
* This is a devious hack; it'd be cleaner to re-create the driver using
@@ -56,7 +59,7 @@ public class SerialConsoleActivity extends Activity {
* can get away with it because both activities will run in the same
* process, and this is a simple demo.
*/
- private static UsbSerialDriver sDriver = null;
+ private static UsbSerialPort sPort = null;
private TextView mTitleTextView;
private TextView mDumpTextView;
@@ -98,13 +101,13 @@ public class SerialConsoleActivity extends Activity {
protected void onPause() {
super.onPause();
stopIoManager();
- if (sDriver != null) {
+ if (sPort != null) {
try {
- sDriver.close();
+ sPort.close();
} catch (IOException e) {
// Ignore.
}
- sDriver = null;
+ sPort = null;
}
finish();
}
@@ -112,25 +115,33 @@ public class SerialConsoleActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
- Log.d(TAG, "Resumed, sDriver=" + sDriver);
- if (sDriver == null) {
+ Log.d(TAG, "Resumed, port=" + sPort);
+ if (sPort == null) {
mTitleTextView.setText("No serial device.");
} else {
+ final UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+
+ UsbDeviceConnection connection = usbManager.openDevice(sPort.getDriver().getDevice());
+ if (connection == null) {
+ mTitleTextView.setText("Opening device failed");
+ return;
+ }
+
try {
- sDriver.open();
- sDriver.setParameters(115200, 8, UsbSerialDriver.STOPBITS_1, UsbSerialDriver.PARITY_NONE);
+ sPort.open(connection);
+ sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
} catch (IOException e) {
Log.e(TAG, "Error setting up device: " + e.getMessage(), e);
mTitleTextView.setText("Error opening device: " + e.getMessage());
try {
- sDriver.close();
+ sPort.close();
} catch (IOException e2) {
// Ignore.
}
- sDriver = null;
+ sPort = null;
return;
}
- mTitleTextView.setText("Serial device: " + sDriver.getClass().getSimpleName());
+ mTitleTextView.setText("Serial device: " + sPort.getClass().getSimpleName());
}
onDeviceStateChange();
}
@@ -144,9 +155,9 @@ public class SerialConsoleActivity extends Activity {
}
private void startIoManager() {
- if (sDriver != null) {
+ if (sPort != null) {
Log.i(TAG, "Starting io manager ..");
- mSerialIoManager = new SerialInputOutputManager(sDriver, mListener);
+ mSerialIoManager = new SerialInputOutputManager(sPort, mListener);
mExecutor.submit(mSerialIoManager);
}
}
@@ -169,8 +180,8 @@ public class SerialConsoleActivity extends Activity {
* @param context
* @param driver
*/
- static void show(Context context, UsbSerialDriver driver) {
- sDriver = driver;
+ static void show(Context context, UsbSerialPort port) {
+ sPort = port;
final Intent intent = new Intent(context, SerialConsoleActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY);
context.startActivity(intent);
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
index 34fa14a..3e764ab 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
@@ -1,3 +1,24 @@
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
+ *
+ * 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: https://github.com/mik3y/usb-serial-for-android
+ */
+
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
@@ -8,7 +29,9 @@ import android.hardware.usb.UsbInterface;
import android.util.Log;
import java.io.IOException;
+import java.util.Collections;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -19,201 +42,243 @@ import java.util.Map;
* href="http://www.usb.org/developers/devclass_docs/usbcdc11.pdf">Universal
* Serial Bus Class Definitions for Communication Devices, v1.1
*/
-public class CdcAcmSerialDriver extends CommonUsbSerialDriver {
+public class CdcAcmSerialDriver implements UsbSerialDriver {
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
- private UsbInterface mControlInterface;
- private UsbInterface mDataInterface;
+ private final UsbDevice mDevice;
+ private final UsbSerialPort mPort;
- private UsbEndpoint mControlEndpoint;
- private UsbEndpoint mReadEndpoint;
- private UsbEndpoint mWriteEndpoint;
-
- private boolean mRts = false;
- private boolean mDtr = false;
-
- private static final int USB_RECIP_INTERFACE = 0x01;
- private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-
- private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
- private static final int GET_LINE_CODING = 0x21;
- private static final int SET_CONTROL_LINE_STATE = 0x22;
- private static final int SEND_BREAK = 0x23;
-
- public CdcAcmSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
- super(device, connection);
+ public CdcAcmSerialDriver(UsbDevice device) {
+ mDevice = device;
+ mPort = new CdcAdcmSerialPort(device);
}
@Override
- public void open() throws IOException {
- Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
+ public UsbDevice getDevice() {
+ return mDevice;
+ }
- Log.d(TAG, "Claiming control interface.");
- mControlInterface = mDevice.getInterface(0);
- Log.d(TAG, "Control iface=" + mControlInterface);
- // class should be USB_CLASS_COMM
+ @Override
+ public List getPorts() {
+ return Collections.singletonList(mPort);
+ }
- if (!mConnection.claimInterface(mControlInterface, true)) {
- throw new IOException("Could not claim control interface.");
+ class CdcAdcmSerialPort extends CommonUsbSerialPort {
+
+ private UsbInterface mControlInterface;
+ private UsbInterface mDataInterface;
+
+ private UsbEndpoint mControlEndpoint;
+ private UsbEndpoint mReadEndpoint;
+ private UsbEndpoint mWriteEndpoint;
+
+ private boolean mRts = false;
+ private boolean mDtr = false;
+
+ private static final int USB_RECIP_INTERFACE = 0x01;
+ private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+
+ private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
+ private static final int GET_LINE_CODING = 0x21;
+ private static final int SET_CONTROL_LINE_STATE = 0x22;
+ private static final int SEND_BREAK = 0x23;
+
+ public CdcAdcmSerialPort(UsbDevice device) {
+ super(device);
}
- mControlEndpoint = mControlInterface.getEndpoint(0);
- Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
- Log.d(TAG, "Claiming data interface.");
- mDataInterface = mDevice.getInterface(1);
- Log.d(TAG, "data iface=" + mDataInterface);
- // class should be USB_CLASS_CDC_DATA
-
- if (!mConnection.claimInterface(mDataInterface, true)) {
- throw new IOException("Could not claim data interface.");
+ @Override
+ public UsbSerialDriver getDriver() {
+ return CdcAcmSerialDriver.this;
}
- mReadEndpoint = mDataInterface.getEndpoint(1);
- Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
- mWriteEndpoint = mDataInterface.getEndpoint(0);
- Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
- }
- private int sendAcmControlMessage(int request, int value, byte[] buf) {
- return mConnection.controlTransfer(
- USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
- }
-
- @Override
- public void close() throws IOException {
- mConnection.close();
- }
-
- @Override
- public int read(byte[] dest, int timeoutMillis) throws IOException {
- final int numBytesRead;
- synchronized (mReadBufferLock) {
- int readAmt = Math.min(dest.length, mReadBuffer.length);
- numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
- timeoutMillis);
- if (numBytesRead < 0) {
- // This sucks: we get -1 on timeout, not 0 as preferred.
- // We *should* use UsbRequest, except it has a bug/api oversight
- // where there is no way to determine the number of bytes read
- // in response :\ -- http://b.android.com/28023
- return 0;
+ @Override
+ public void open(UsbDeviceConnection connection) throws IOException {
+ if (mConnection != null) {
+ throw new IOException("Already open");
+ }
+
+ mConnection = connection;
+ boolean opened = false;
+ try {
+ Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
+ mControlInterface = mDevice.getInterface(0);
+ Log.d(TAG, "Control iface=" + mControlInterface);
+ // class should be USB_CLASS_COMM
+
+ if (!mConnection.claimInterface(mControlInterface, true)) {
+ throw new IOException("Could not claim control interface.");
+ }
+ mControlEndpoint = mControlInterface.getEndpoint(0);
+ Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
+
+ Log.d(TAG, "Claiming data interface.");
+ mDataInterface = mDevice.getInterface(1);
+ Log.d(TAG, "data iface=" + mDataInterface);
+ // class should be USB_CLASS_CDC_DATA
+
+ if (!mConnection.claimInterface(mDataInterface, true)) {
+ throw new IOException("Could not claim data interface.");
+ }
+ mReadEndpoint = mDataInterface.getEndpoint(1);
+ Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
+ mWriteEndpoint = mDataInterface.getEndpoint(0);
+ Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
+ opened = true;
+ } finally {
+ if (!opened) {
+ mConnection = null;
+ }
}
- System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
- return numBytesRead;
- }
- @Override
- public int write(byte[] src, int timeoutMillis) throws IOException {
- // TODO(mikey): Nearly identical to FtdiSerial write. Refactor.
- int offset = 0;
+ private int sendAcmControlMessage(int request, int value, byte[] buf) {
+ return mConnection.controlTransfer(
+ USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
+ }
- while (offset < src.length) {
- final int writeLength;
- final int amtWritten;
+ @Override
+ public void close() throws IOException {
+ if (mConnection == null) {
+ throw new IOException("Already closed");
+ }
+ mConnection.close();
+ mConnection = null;
+ }
- synchronized (mWriteBufferLock) {
- final byte[] writeBuffer;
+ @Override
+ public int read(byte[] dest, int timeoutMillis) throws IOException {
+ final int numBytesRead;
+ synchronized (mReadBufferLock) {
+ int readAmt = Math.min(dest.length, mReadBuffer.length);
+ numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
+ timeoutMillis);
+ if (numBytesRead < 0) {
+ // This sucks: we get -1 on timeout, not 0 as preferred.
+ // We *should* use UsbRequest, except it has a bug/api oversight
+ // where there is no way to determine the number of bytes read
+ // in response :\ -- http://b.android.com/28023
+ return 0;
+ }
+ System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
+ }
+ return numBytesRead;
+ }
- writeLength = Math.min(src.length - offset, mWriteBuffer.length);
- if (offset == 0) {
- writeBuffer = src;
- } else {
- // bulkTransfer does not support offsets, make a copy.
- System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
- writeBuffer = mWriteBuffer;
+ @Override
+ public int write(byte[] src, int timeoutMillis) throws IOException {
+ // TODO(mikey): Nearly identical to FtdiSerial write. Refactor.
+ int offset = 0;
+
+ while (offset < src.length) {
+ final int writeLength;
+ final int amtWritten;
+
+ synchronized (mWriteBufferLock) {
+ final byte[] writeBuffer;
+
+ writeLength = Math.min(src.length - offset, mWriteBuffer.length);
+ if (offset == 0) {
+ writeBuffer = src;
+ } else {
+ // bulkTransfer does not support offsets, make a copy.
+ System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
+ writeBuffer = mWriteBuffer;
+ }
+
+ amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
+ timeoutMillis);
+ }
+ if (amtWritten <= 0) {
+ throw new IOException("Error writing " + writeLength
+ + " bytes at offset " + offset + " length=" + src.length);
}
- amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
- timeoutMillis);
+ Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
+ offset += amtWritten;
}
- if (amtWritten <= 0) {
- throw new IOException("Error writing " + writeLength
- + " bytes at offset " + offset + " length=" + src.length);
+ return offset;
+ }
+
+ @Override
+ public void setParameters(int baudRate, int dataBits, int stopBits, int parity) {
+ byte stopBitsByte;
+ switch (stopBits) {
+ case STOPBITS_1: stopBitsByte = 0; break;
+ case STOPBITS_1_5: stopBitsByte = 1; break;
+ case STOPBITS_2: stopBitsByte = 2; break;
+ default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits);
}
- Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
- offset += amtWritten;
- }
- return offset;
- }
+ byte parityBitesByte;
+ switch (parity) {
+ case PARITY_NONE: parityBitesByte = 0; break;
+ case PARITY_ODD: parityBitesByte = 1; break;
+ case PARITY_EVEN: parityBitesByte = 2; break;
+ case PARITY_MARK: parityBitesByte = 3; break;
+ case PARITY_SPACE: parityBitesByte = 4; break;
+ default: throw new IllegalArgumentException("Bad value for parity: " + parity);
+ }
- @Override
- public void setParameters(int baudRate, int dataBits, int stopBits, int parity) {
- byte stopBitsByte;
- switch (stopBits) {
- case STOPBITS_1: stopBitsByte = 0; break;
- case STOPBITS_1_5: stopBitsByte = 1; break;
- case STOPBITS_2: stopBitsByte = 2; break;
- default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits);
+ byte[] msg = {
+ (byte) ( baudRate & 0xff),
+ (byte) ((baudRate >> 8 ) & 0xff),
+ (byte) ((baudRate >> 16) & 0xff),
+ (byte) ((baudRate >> 24) & 0xff),
+ stopBitsByte,
+ parityBitesByte,
+ (byte) dataBits};
+ sendAcmControlMessage(SET_LINE_CODING, 0, msg);
}
- byte parityBitesByte;
- switch (parity) {
- case PARITY_NONE: parityBitesByte = 0; break;
- case PARITY_ODD: parityBitesByte = 1; break;
- case PARITY_EVEN: parityBitesByte = 2; break;
- case PARITY_MARK: parityBitesByte = 3; break;
- case PARITY_SPACE: parityBitesByte = 4; break;
- default: throw new IllegalArgumentException("Bad value for parity: " + parity);
+ @Override
+ public boolean getCD() throws IOException {
+ return false; // TODO
}
- byte[] msg = {
- (byte) ( baudRate & 0xff),
- (byte) ((baudRate >> 8 ) & 0xff),
- (byte) ((baudRate >> 16) & 0xff),
- (byte) ((baudRate >> 24) & 0xff),
- stopBitsByte,
- parityBitesByte,
- (byte) dataBits};
- sendAcmControlMessage(SET_LINE_CODING, 0, msg);
- }
+ @Override
+ public boolean getCTS() throws IOException {
+ return false; // TODO
+ }
- @Override
- public boolean getCD() throws IOException {
- return false; // TODO
- }
+ @Override
+ public boolean getDSR() throws IOException {
+ return false; // TODO
+ }
- @Override
- public boolean getCTS() throws IOException {
- return false; // TODO
- }
+ @Override
+ public boolean getDTR() throws IOException {
+ return mDtr;
+ }
- @Override
- public boolean getDSR() throws IOException {
- return false; // TODO
- }
+ @Override
+ public void setDTR(boolean value) throws IOException {
+ mDtr = value;
+ setDtrRts();
+ }
- @Override
- public boolean getDTR() throws IOException {
- return mDtr;
- }
+ @Override
+ public boolean getRI() throws IOException {
+ return false; // TODO
+ }
- @Override
- public void setDTR(boolean value) throws IOException {
- mDtr = value;
- setDtrRts();
- }
+ @Override
+ public boolean getRTS() throws IOException {
+ return mRts;
+ }
- @Override
- public boolean getRI() throws IOException {
- return false; // TODO
- }
+ @Override
+ public void setRTS(boolean value) throws IOException {
+ mRts = value;
+ setDtrRts();
+ }
- @Override
- public boolean getRTS() throws IOException {
- return mRts;
- }
+ private void setDtrRts() {
+ int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
+ sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
+ }
- @Override
- public void setRTS(boolean value) throws IOException {
- mRts = value;
- setDtrRts();
- }
-
- private void setDtrRts() {
- int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
- sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
}
public static Map getSupportedDevices() {
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java
similarity index 90%
rename from UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java
rename to UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java
index 7c61704..d8a9e1f 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java
@@ -1,4 +1,5 @@
-/* Copyright 2013 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.driver;
@@ -30,13 +31,15 @@ import java.io.IOException;
*
* @author mike wakerly (opensource@hoho.com)
*/
-abstract class CommonUsbSerialDriver implements UsbSerialDriver {
+abstract class CommonUsbSerialPort implements UsbSerialPort {
public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024;
public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
protected final UsbDevice mDevice;
- protected final UsbDeviceConnection mConnection;
+
+ // non-null when open()
+ protected UsbDeviceConnection mConnection = null;
protected final Object mReadBufferLock = new Object();
protected final Object mWriteBufferLock = new Object();
@@ -47,9 +50,8 @@ abstract class CommonUsbSerialDriver implements UsbSerialDriver {
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected byte[] mWriteBuffer;
- public CommonUsbSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
+ public CommonUsbSerialPort(UsbDevice device) {
mDevice = device;
- mConnection = connection;
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
@@ -95,7 +97,7 @@ abstract class CommonUsbSerialDriver implements UsbSerialDriver {
}
@Override
- public abstract void open() throws IOException;
+ public abstract void open(UsbDeviceConnection connection) throws IOException;
@Override
public abstract void close() throws IOException;
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
index 7e9118b..a427a18 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
@@ -1,8 +1,25 @@
-package com.hoho.android.usbserial.driver;
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
+ *
+ * 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: https://github.com/mik3y/usb-serial-for-android
+ */
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Map;
+package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
@@ -11,273 +28,323 @@ import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
-public class Cp2102SerialDriver extends CommonUsbSerialDriver {
- private static final String TAG = Cp2102SerialDriver.class.getSimpleName();
-
- private static final int DEFAULT_BAUD_RATE = 9600;
-
- private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
-
- /*
- * Configuration Request Types
- */
- private static final int REQTYPE_HOST_TO_DEVICE = 0x41;
-
- /*
- * Configuration Request Codes
- */
- private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00;
- private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01;
- private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03;
- private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07;
- private static final int SILABSER_SET_BAUDRATE = 0x1E;
- private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12;
-
- private static final int FLUSH_READ_CODE = 0x0a;
- private static final int FLUSH_WRITE_CODE = 0x05;
-
- /*
- * SILABSER_IFC_ENABLE_REQUEST_CODE
- */
- private static final int UART_ENABLE = 0x0001;
- private static final int UART_DISABLE = 0x0000;
-
- /*
- * SILABSER_SET_BAUDDIV_REQUEST_CODE
- */
- private static final int BAUD_RATE_GEN_FREQ = 0x384000;
-
- /*
- * SILABSER_SET_MHS_REQUEST_CODE
- */
- private static final int MCR_DTR = 0x0001;
- private static final int MCR_RTS = 0x0002;
- private static final int MCR_ALL = 0x0003;
-
- private static final int CONTROL_WRITE_DTR = 0x0100;
- private static final int CONTROL_WRITE_RTS = 0x0200;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
- private UsbEndpoint mReadEndpoint;
- private UsbEndpoint mWriteEndpoint;
-
- public Cp2102SerialDriver(UsbDevice device, UsbDeviceConnection connection) {
- super(device, connection);
- }
-
- private int setConfigSingle(int request, int value) {
- return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,
- 0, null, 0, USB_WRITE_TIMEOUT_MILLIS);
+public class Cp2102SerialDriver implements UsbSerialDriver {
+
+ private static final String TAG = Cp2102SerialDriver.class.getSimpleName();
+
+ private final UsbDevice mDevice;
+ private final UsbSerialPort mPort;
+
+ public Cp2102SerialDriver(UsbDevice device) {
+ mDevice = device;
+ mPort = new Cp2102SerialPort(mDevice);
}
@Override
- public void open() throws IOException {
- boolean opened = false;
- try {
- for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
- UsbInterface usbIface = mDevice.getInterface(i);
- if (mConnection.claimInterface(usbIface, true)) {
- Log.d(TAG, "claimInterface " + i + " SUCCESS");
- } else {
- Log.d(TAG, "claimInterface " + i + " FAIL");
- }
- }
-
- UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
- for (int i = 0; i < dataIface.getEndpointCount(); i++) {
- UsbEndpoint ep = dataIface.getEndpoint(i);
- if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
- if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
- mReadEndpoint = ep;
+ public UsbDevice getDevice() {
+ return mDevice;
+ }
+
+ @Override
+ public List getPorts() {
+ return Collections.singletonList(mPort);
+ }
+
+ class Cp2102SerialPort extends CommonUsbSerialPort {
+
+ private static final int DEFAULT_BAUD_RATE = 9600;
+
+ private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
+
+ /*
+ * Configuration Request Types
+ */
+ private static final int REQTYPE_HOST_TO_DEVICE = 0x41;
+
+ /*
+ * Configuration Request Codes
+ */
+ private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00;
+ private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01;
+ private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03;
+ private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07;
+ private static final int SILABSER_SET_BAUDRATE = 0x1E;
+ private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12;
+
+ private static final int FLUSH_READ_CODE = 0x0a;
+ private static final int FLUSH_WRITE_CODE = 0x05;
+
+ /*
+ * SILABSER_IFC_ENABLE_REQUEST_CODE
+ */
+ private static final int UART_ENABLE = 0x0001;
+ private static final int UART_DISABLE = 0x0000;
+
+ /*
+ * SILABSER_SET_BAUDDIV_REQUEST_CODE
+ */
+ private static final int BAUD_RATE_GEN_FREQ = 0x384000;
+
+ /*
+ * SILABSER_SET_MHS_REQUEST_CODE
+ */
+ private static final int MCR_DTR = 0x0001;
+ private static final int MCR_RTS = 0x0002;
+ private static final int MCR_ALL = 0x0003;
+
+ private static final int CONTROL_WRITE_DTR = 0x0100;
+ private static final int CONTROL_WRITE_RTS = 0x0200;
+
+ private UsbEndpoint mReadEndpoint;
+ private UsbEndpoint mWriteEndpoint;
+
+ public Cp2102SerialPort(UsbDevice device) {
+ super(device);
+ }
+
+ @Override
+ public UsbSerialDriver getDriver() {
+ return Cp2102SerialDriver.this;
+ }
+
+ private int setConfigSingle(int request, int value) {
+ return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,
+ 0, null, 0, USB_WRITE_TIMEOUT_MILLIS);
+ }
+
+ @Override
+ public void open(UsbDeviceConnection connection) throws IOException {
+ if (mConnection != null) {
+ throw new IOException("Already opened.");
+ }
+
+ mConnection = connection;
+ boolean opened = false;
+ try {
+ for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
+ UsbInterface usbIface = mDevice.getInterface(i);
+ if (mConnection.claimInterface(usbIface, true)) {
+ Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
- mWriteEndpoint = ep;
+ Log.d(TAG, "claimInterface " + i + " FAIL");
+ }
+ }
+
+ UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
+ for (int i = 0; i < dataIface.getEndpointCount(); i++) {
+ UsbEndpoint ep = dataIface.getEndpoint(i);
+ if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
+ if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
+ mReadEndpoint = ep;
+ } else {
+ mWriteEndpoint = ep;
+ }
+ }
+ }
+
+ setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE);
+ setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS);
+ setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE);
+ // setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY);
+ opened = true;
+ } finally {
+ if (!opened) {
+ try {
+ close();
+ } catch (IOException e) {
+ // Ignore IOExceptions during close()
}
}
}
-
- setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE);
- setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS);
- setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE);
-// setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY);
- opened = true;
- } finally {
- if (!opened) {
- close();
- }
- }
- }
-
- @Override
- public void close() throws IOException {
- setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
- mConnection.close();
- }
-
- @Override
- public int read(byte[] dest, int timeoutMillis) throws IOException {
- final int numBytesRead;
- synchronized (mReadBufferLock) {
- int readAmt = Math.min(dest.length, mReadBuffer.length);
- numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
- timeoutMillis);
- if (numBytesRead < 0) {
- // This sucks: we get -1 on timeout, not 0 as preferred.
- // We *should* use UsbRequest, except it has a bug/api oversight
- // where there is no way to determine the number of bytes read
- // in response :\ -- http://b.android.com/28023
- return 0;
- }
- System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
- return numBytesRead;
- }
- @Override
- public int write(byte[] src, int timeoutMillis) throws IOException {
- int offset = 0;
+ @Override
+ public void close() throws IOException {
+ if (mConnection == null) {
+ throw new IOException("Already closed");
+ }
+ try {
+ setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
+ mConnection.close();
+ } finally {
+ mConnection = null;
+ }
+ }
- while (offset < src.length) {
- final int writeLength;
- final int amtWritten;
+ @Override
+ public int read(byte[] dest, int timeoutMillis) throws IOException {
+ final int numBytesRead;
+ synchronized (mReadBufferLock) {
+ int readAmt = Math.min(dest.length, mReadBuffer.length);
+ numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
+ timeoutMillis);
+ if (numBytesRead < 0) {
+ // This sucks: we get -1 on timeout, not 0 as preferred.
+ // We *should* use UsbRequest, except it has a bug/api oversight
+ // where there is no way to determine the number of bytes read
+ // in response :\ -- http://b.android.com/28023
+ return 0;
+ }
+ System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
+ }
+ return numBytesRead;
+ }
- synchronized (mWriteBufferLock) {
- final byte[] writeBuffer;
+ @Override
+ public int write(byte[] src, int timeoutMillis) throws IOException {
+ int offset = 0;
- writeLength = Math.min(src.length - offset, mWriteBuffer.length);
- if (offset == 0) {
- writeBuffer = src;
- } else {
- // bulkTransfer does not support offsets, make a copy.
- System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
- writeBuffer = mWriteBuffer;
+ while (offset < src.length) {
+ final int writeLength;
+ final int amtWritten;
+
+ synchronized (mWriteBufferLock) {
+ final byte[] writeBuffer;
+
+ writeLength = Math.min(src.length - offset, mWriteBuffer.length);
+ if (offset == 0) {
+ writeBuffer = src;
+ } else {
+ // bulkTransfer does not support offsets, make a copy.
+ System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
+ writeBuffer = mWriteBuffer;
+ }
+
+ amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
+ timeoutMillis);
+ }
+ if (amtWritten <= 0) {
+ throw new IOException("Error writing " + writeLength
+ + " bytes at offset " + offset + " length=" + src.length);
}
- amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
- timeoutMillis);
+ Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
+ offset += amtWritten;
}
- if (amtWritten <= 0) {
- throw new IOException("Error writing " + writeLength
- + " bytes at offset " + offset + " length=" + src.length);
+ return offset;
+ }
+
+ private void setBaudRate(int baudRate) throws IOException {
+ byte[] data = new byte[] {
+ (byte) ( baudRate & 0xff),
+ (byte) ((baudRate >> 8 ) & 0xff),
+ (byte) ((baudRate >> 16) & 0xff),
+ (byte) ((baudRate >> 24) & 0xff)
+ };
+ int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
+ 0, 0, data, 4, USB_WRITE_TIMEOUT_MILLIS);
+ if (ret < 0) {
+ throw new IOException("Error setting baud rate.");
}
-
- Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
- offset += amtWritten;
- }
- return offset;
- }
-
- private void setBaudRate(int baudRate) throws IOException {
- byte[] data = new byte[] {
- (byte) ( baudRate & 0xff),
- (byte) ((baudRate >> 8 ) & 0xff),
- (byte) ((baudRate >> 16) & 0xff),
- (byte) ((baudRate >> 24) & 0xff)
- };
- int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
- 0, 0, data, 4, USB_WRITE_TIMEOUT_MILLIS);
- if (ret < 0) {
- throw new IOException("Error setting baud rate.");
- }
- }
-
- @Override
- public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
- throws IOException {
- setBaudRate(baudRate);
-
- int configDataBits = 0;
- switch (dataBits) {
- case DATABITS_5:
- configDataBits |= 0x0500;
- break;
- case DATABITS_6:
- configDataBits |= 0x0600;
- break;
- case DATABITS_7:
- configDataBits |= 0x0700;
- break;
- case DATABITS_8:
- configDataBits |= 0x0800;
- break;
- default:
- configDataBits |= 0x0800;
- break;
- }
- setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
-
- int configParityBits = 0; // PARITY_NONE
- switch (parity) {
- case PARITY_ODD:
- configParityBits |= 0x0010;
- break;
- case PARITY_EVEN:
- configParityBits |= 0x0020;
- break;
- }
- setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configParityBits);
-
- int configStopBits = 0;
- switch (stopBits) {
- case STOPBITS_1:
- configStopBits |= 0;
- break;
- case STOPBITS_2:
- configStopBits |= 2;
- break;
- }
- setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configStopBits);
- }
-
- @Override
- public boolean getCD() throws IOException {
- return false;
- }
-
- @Override
- public boolean getCTS() throws IOException {
- return false;
- }
-
- @Override
- public boolean getDSR() throws IOException {
- return false;
- }
-
- @Override
- public boolean getDTR() throws IOException {
- return true;
- }
-
- @Override
- public void setDTR(boolean value) throws IOException {
- }
-
- @Override
- public boolean getRI() throws IOException {
- return false;
- }
-
- @Override
- public boolean getRTS() throws IOException {
- return true;
- }
-
- @Override
- public boolean purgeHwBuffers(boolean purgeReadBuffers,
- boolean purgeWriteBuffers) throws IOException {
- int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
- | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
-
- if (value != 0) {
- setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
}
- return true;
+ @Override
+ public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
+ throws IOException {
+ setBaudRate(baudRate);
+
+ int configDataBits = 0;
+ switch (dataBits) {
+ case DATABITS_5:
+ configDataBits |= 0x0500;
+ break;
+ case DATABITS_6:
+ configDataBits |= 0x0600;
+ break;
+ case DATABITS_7:
+ configDataBits |= 0x0700;
+ break;
+ case DATABITS_8:
+ configDataBits |= 0x0800;
+ break;
+ default:
+ configDataBits |= 0x0800;
+ break;
+ }
+ setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
+
+ int configParityBits = 0; // PARITY_NONE
+ switch (parity) {
+ case PARITY_ODD:
+ configParityBits |= 0x0010;
+ break;
+ case PARITY_EVEN:
+ configParityBits |= 0x0020;
+ break;
+ }
+ setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configParityBits);
+
+ int configStopBits = 0;
+ switch (stopBits) {
+ case STOPBITS_1:
+ configStopBits |= 0;
+ break;
+ case STOPBITS_2:
+ configStopBits |= 2;
+ break;
+ }
+ setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configStopBits);
+ }
+
+ @Override
+ public boolean getCD() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getCTS() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getDSR() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getDTR() throws IOException {
+ return true;
+ }
+
+ @Override
+ public void setDTR(boolean value) throws IOException {
+ }
+
+ @Override
+ public boolean getRI() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getRTS() throws IOException {
+ return true;
+ }
+
+ @Override
+ public void setRTS(boolean value) throws IOException {
+ }
+
+ @Override
+ public boolean purgeHwBuffers(boolean purgeReadBuffers,
+ boolean purgeWriteBuffers) throws IOException {
+ int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
+ | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
+
+ if (value != 0) {
+ setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
+ }
+
+ return true;
+ }
+
}
- @Override
- public void setRTS(boolean value) throws IOException {
- }
-
public static Map getSupportedDevices() {
final Map supportedDevices = new LinkedHashMap();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILAB),
@@ -287,5 +354,4 @@ public class Cp2102SerialDriver extends CommonUsbSerialDriver {
return supportedDevices;
}
-
}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
index caaa4ec..7aad732 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
@@ -1,4 +1,5 @@
-/* Copyright 2011 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.driver;
@@ -31,14 +32,16 @@ import com.hoho.android.usbserial.util.HexDump;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
/**
- * A {@link CommonUsbSerialDriver} implementation for a variety of FTDI devices
+ * A {@link CommonUsbSerialPort} implementation for a variety of FTDI devices
*
- * This driver is based on
- * libftdi, and is
+ * This driver is based on libftdi, and is
* copyright and subject to the following terms:
*
*
@@ -58,9 +61,11 @@ import java.util.Map;
* unsupported devices. Devices listed as "supported" support the following
* features:
*
- * - Read and write of serial data (see {@link #read(byte[], int)} and
- * {@link #write(byte[], int)}.
- *
- Setting baud rate (see {@link #setBaudRate(int)}).
+ *
- Read and write of serial data (see
+ * {@link CommonUsbSerialPort#read(byte[], int)} and
+ * {@link CommonUsbSerialPort#write(byte[], int)}.
+ * - Setting serial line parameters (see
+ * {@link CommonUsbSerialPort#setParameters(int, int, int, int)}.
*
*
*
@@ -82,73 +87,15 @@ import java.util.Map;
*
*
* @author mike wakerly (opensource@hoho.com)
- * @see USB Serial
- * for Android project page
+ * @see USB Serial
+ * for Android project page
* @see FTDI Homepage
* @see libftdi
*/
-public class FtdiSerialDriver extends CommonUsbSerialDriver {
+public class FtdiSerialDriver implements UsbSerialDriver {
- public static final int USB_TYPE_STANDARD = 0x00 << 5;
- public static final int USB_TYPE_CLASS = 0x01 << 5;
- public static final int USB_TYPE_VENDOR = 0x02 << 5;
- public static final int USB_TYPE_RESERVED = 0x03 << 5;
-
- public static final int USB_RECIP_DEVICE = 0x00;
- public static final int USB_RECIP_INTERFACE = 0x01;
- public static final int USB_RECIP_ENDPOINT = 0x02;
- public static final int USB_RECIP_OTHER = 0x03;
-
- public static final int USB_ENDPOINT_IN = 0x80;
- public static final int USB_ENDPOINT_OUT = 0x00;
-
- public static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
- public static final int USB_READ_TIMEOUT_MILLIS = 5000;
-
- // From ftdi.h
- /**
- * Reset the port.
- */
- private static final int SIO_RESET_REQUEST = 0;
-
- /**
- * Set the modem control register.
- */
- private static final int SIO_MODEM_CTRL_REQUEST = 1;
-
- /**
- * Set flow control register.
- */
- private static final int SIO_SET_FLOW_CTRL_REQUEST = 2;
-
- /**
- * Set baud rate.
- */
- private static final int SIO_SET_BAUD_RATE_REQUEST = 3;
-
- /**
- * Set the data characteristics of the port.
- */
- private static final int SIO_SET_DATA_REQUEST = 4;
-
- private static final int SIO_RESET_SIO = 0;
- private static final int SIO_RESET_PURGE_RX = 1;
- private static final int SIO_RESET_PURGE_TX = 2;
-
- public static final int FTDI_DEVICE_OUT_REQTYPE =
- UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT;
-
- public static final int FTDI_DEVICE_IN_REQTYPE =
- UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;
-
- /**
- * Length of the modem status header, transmitted with every read.
- */
- private static final int MODEM_STATUS_HEADER_LENGTH = 2;
-
- private final String TAG = FtdiSerialDriver.class.getSimpleName();
-
- private DeviceType mType;
+ private final UsbDevice mDevice;
+ private final UsbSerialPort mPort;
/**
* FTDI chip types.
@@ -157,382 +104,467 @@ public class FtdiSerialDriver extends CommonUsbSerialDriver {
TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H;
}
- private int mInterface = 0; /* INTERFACE_ANY */
-
- private int mMaxPacketSize = 64; // TODO(mikey): detect
-
- /**
- * Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
- * since it gives no indication of number of bytes read. Set this to
- * {@code true} on platforms where it is fixed.
- */
- private static final boolean ENABLE_ASYNC_READS = false;
-
- /**
- * Filter FTDI status bytes from buffer
- * @param src The source buffer (which contains status bytes)
- * @param dest The destination buffer to write the status bytes into (can be src)
- * @param totalBytesRead Number of bytes read to src
- * @param maxPacketSize The USB endpoint max packet size
- * @return The number of payload bytes
- */
- private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) {
- final int packetsCount = totalBytesRead / maxPacketSize + 1;
- for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) {
- final int count = (packetIdx == (packetsCount - 1))
- ? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH
- : maxPacketSize - MODEM_STATUS_HEADER_LENGTH;
- if (count > 0) {
- System.arraycopy(src,
- packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH,
- dest,
- packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH),
- count);
- }
- }
-
- return totalBytesRead - (packetsCount * 2);
+ public FtdiSerialDriver(UsbDevice device) {
+ mDevice = device;
+ mPort = new FtdiSerialPort(mDevice);
}
-
- /**
- * Constructor.
- *
- * @param usbDevice the {@link UsbDevice} to use
- * @param usbConnection the {@link UsbDeviceConnection} to use
- * @throws UsbSerialRuntimeException if the given device is incompatible
- * with this driver
- */
- public FtdiSerialDriver(UsbDevice usbDevice, UsbDeviceConnection usbConnection) {
- super(usbDevice, usbConnection);
- mType = null;
- }
-
- public void reset() throws IOException {
- int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
- SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
- if (result != 0) {
- throw new IOException("Reset failed: result=" + result);
- }
-
- // TODO(mikey): autodetect.
- mType = DeviceType.TYPE_R;
+ @Override
+ public UsbDevice getDevice() {
+ return mDevice;
}
@Override
- public void open() throws IOException {
- boolean opened = false;
- try {
- for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
- if (mConnection.claimInterface(mDevice.getInterface(i), true)) {
- Log.d(TAG, "claimInterface " + i + " SUCCESS");
- } else {
- throw new IOException("Error claiming interface " + i);
+ public List getPorts() {
+ return Collections.singletonList(mPort);
+ }
+
+ private class FtdiSerialPort extends CommonUsbSerialPort {
+
+ public static final int USB_TYPE_STANDARD = 0x00 << 5;
+ public static final int USB_TYPE_CLASS = 0x00 << 5;
+ public static final int USB_TYPE_VENDOR = 0x00 << 5;
+ public static final int USB_TYPE_RESERVED = 0x00 << 5;
+
+ public static final int USB_RECIP_DEVICE = 0x00;
+ public static final int USB_RECIP_INTERFACE = 0x01;
+ public static final int USB_RECIP_ENDPOINT = 0x02;
+ public static final int USB_RECIP_OTHER = 0x03;
+
+ public static final int USB_ENDPOINT_IN = 0x80;
+ public static final int USB_ENDPOINT_OUT = 0x00;
+
+ public static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
+ public static final int USB_READ_TIMEOUT_MILLIS = 5000;
+
+ // From ftdi.h
+ /**
+ * Reset the port.
+ */
+ private static final int SIO_RESET_REQUEST = 0;
+
+ /**
+ * Set the modem control register.
+ */
+ private static final int SIO_MODEM_CTRL_REQUEST = 1;
+
+ /**
+ * Set flow control register.
+ */
+ private static final int SIO_SET_FLOW_CTRL_REQUEST = 2;
+
+ /**
+ * Set baud rate.
+ */
+ private static final int SIO_SET_BAUD_RATE_REQUEST = 3;
+
+ /**
+ * Set the data characteristics of the port.
+ */
+ private static final int SIO_SET_DATA_REQUEST = 4;
+
+ private static final int SIO_RESET_SIO = 0;
+ private static final int SIO_RESET_PURGE_RX = 1;
+ private static final int SIO_RESET_PURGE_TX = 2;
+
+ public static final int FTDI_DEVICE_OUT_REQTYPE =
+ UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT;
+
+ public static final int FTDI_DEVICE_IN_REQTYPE =
+ UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;
+
+ /**
+ * Length of the modem status header, transmitted with every read.
+ */
+ private static final int MODEM_STATUS_HEADER_LENGTH = 2;
+
+ private final String TAG = FtdiSerialDriver.class.getSimpleName();
+
+ private DeviceType mType;
+
+ private int mInterface = 0; /* INTERFACE_ANY */
+
+ private int mMaxPacketSize = 64; // TODO(mikey): detect
+
+ /**
+ * Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
+ * since it gives no indication of number of bytes read. Set this to
+ * {@code true} on platforms where it is fixed.
+ */
+ private static final boolean ENABLE_ASYNC_READS = false;
+
+ public FtdiSerialPort(UsbDevice device) {
+ super(device);
+ }
+
+ @Override
+ public UsbSerialDriver getDriver() {
+ return FtdiSerialDriver.this;
+ }
+
+ /**
+ * Filter FTDI status bytes from buffer
+ * @param src The source buffer (which contains status bytes)
+ * @param dest The destination buffer to write the status bytes into (can be src)
+ * @param totalBytesRead Number of bytes read to src
+ * @param maxPacketSize The USB endpoint max packet size
+ * @return The number of payload bytes
+ */
+ private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) {
+ final int packetsCount = totalBytesRead / maxPacketSize + 1;
+ for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) {
+ final int count = (packetIdx == (packetsCount - 1))
+ ? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH
+ : maxPacketSize - MODEM_STATUS_HEADER_LENGTH;
+ if (count > 0) {
+ System.arraycopy(src,
+ packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH,
+ dest,
+ packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH),
+ count);
}
}
- reset();
- opened = true;
- } finally {
- if (!opened) {
- close();
+
+ return totalBytesRead - (packetsCount * 2);
+ }
+
+ public void reset() throws IOException {
+ int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
+ SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
+ if (result != 0) {
+ throw new IOException("Reset failed: result=" + result);
+ }
+
+ // TODO(mikey): autodetect.
+ mType = DeviceType.TYPE_R;
+ }
+
+ @Override
+ public void open(UsbDeviceConnection connection) throws IOException {
+ if (mConnection != null) {
+ throw new IOException("Already open");
+ }
+ boolean opened = false;
+ try {
+ for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
+ if (mConnection.claimInterface(mDevice.getInterface(i), true)) {
+ Log.d(TAG, "claimInterface " + i + " SUCCESS");
+ } else {
+ throw new IOException("Error claiming interface " + i);
+ }
+ }
+ reset();
+ opened = true;
+ } finally {
+ if (!opened) {
+ close();
+ } else {
+ mConnection = connection;
+ }
}
}
- }
- @Override
- public void close() {
- mConnection.close();
- }
-
- @Override
- public int read(byte[] dest, int timeoutMillis) throws IOException {
- final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
-
- if (ENABLE_ASYNC_READS) {
- final int readAmt;
- synchronized (mReadBufferLock) {
- // mReadBuffer is only used for maximum read size.
- readAmt = Math.min(dest.length, mReadBuffer.length);
+ @Override
+ public void close() throws IOException {
+ if (mConnection == null) {
+ throw new IOException("Already closed");
}
-
- final UsbRequest request = new UsbRequest();
- request.initialize(mConnection, endpoint);
-
- final ByteBuffer buf = ByteBuffer.wrap(dest);
- if (!request.queue(buf, readAmt)) {
- throw new IOException("Error queueing request.");
+ try {
+ mConnection.close();
+ } finally {
+ mConnection = null;
}
+ }
- final UsbRequest response = mConnection.requestWait();
- if (response == null) {
- throw new IOException("Null response");
- }
+ @Override
+ public int read(byte[] dest, int timeoutMillis) throws IOException {
+ final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
- final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
- if (payloadBytesRead > 0) {
- Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
- return payloadBytesRead;
+ if (ENABLE_ASYNC_READS) {
+ final int readAmt;
+ synchronized (mReadBufferLock) {
+ // mReadBuffer is only used for maximum read size.
+ readAmt = Math.min(dest.length, mReadBuffer.length);
+ }
+
+ final UsbRequest request = new UsbRequest();
+ request.initialize(mConnection, endpoint);
+
+ final ByteBuffer buf = ByteBuffer.wrap(dest);
+ if (!request.queue(buf, readAmt)) {
+ throw new IOException("Error queueing request.");
+ }
+
+ final UsbRequest response = mConnection.requestWait();
+ if (response == null) {
+ throw new IOException("Null response");
+ }
+
+ final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
+ if (payloadBytesRead > 0) {
+ Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
+ return payloadBytesRead;
+ } else {
+ return 0;
+ }
} else {
- return 0;
- }
- } else {
- final int totalBytesRead;
+ final int totalBytesRead;
- synchronized (mReadBufferLock) {
- final int readAmt = Math.min(dest.length, mReadBuffer.length);
- totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
- readAmt, timeoutMillis);
+ 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");
+ if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
+ throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
+ }
+
+ return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());
}
-
- return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());
}
}
- }
- @Override
- public int write(byte[] src, int timeoutMillis) throws IOException {
- final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1);
- int offset = 0;
+ @Override
+ public int write(byte[] src, int timeoutMillis) throws IOException {
+ final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1);
+ int offset = 0;
- while (offset < src.length) {
- final int writeLength;
- final int amtWritten;
+ while (offset < src.length) {
+ final int writeLength;
+ final int amtWritten;
- synchronized (mWriteBufferLock) {
- final byte[] writeBuffer;
+ synchronized (mWriteBufferLock) {
+ final byte[] writeBuffer;
- writeLength = Math.min(src.length - offset, mWriteBuffer.length);
- if (offset == 0) {
- writeBuffer = src;
- } else {
- // bulkTransfer does not support offsets, make a copy.
- System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
- writeBuffer = mWriteBuffer;
+ writeLength = Math.min(src.length - offset, mWriteBuffer.length);
+ if (offset == 0) {
+ writeBuffer = src;
+ } else {
+ // bulkTransfer does not support offsets, make a copy.
+ System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
+ writeBuffer = mWriteBuffer;
+ }
+
+ amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength,
+ timeoutMillis);
}
- amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength,
- timeoutMillis);
+ if (amtWritten <= 0) {
+ throw new IOException("Error writing " + writeLength
+ + " bytes at offset " + offset + " length=" + src.length);
+ }
+
+ Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength);
+ offset += amtWritten;
+ }
+ return offset;
+ }
+
+ private int setBaudRate(int baudRate) throws IOException {
+ long[] vals = convertBaudrate(baudRate);
+ long actualBaudrate = vals[0];
+ long index = vals[1];
+ long value = vals[2];
+ int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
+ SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index,
+ null, 0, USB_WRITE_TIMEOUT_MILLIS);
+ if (result != 0) {
+ throw new IOException("Setting baudrate failed: result=" + result);
+ }
+ return (int) actualBaudrate;
+ }
+
+ @Override
+ public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
+ throws IOException {
+ setBaudRate(baudRate);
+
+ int config = dataBits;
+
+ switch (parity) {
+ case PARITY_NONE:
+ config |= (0x00 << 8);
+ break;
+ case PARITY_ODD:
+ config |= (0x01 << 8);
+ break;
+ case PARITY_EVEN:
+ config |= (0x02 << 8);
+ break;
+ case PARITY_MARK:
+ config |= (0x03 << 8);
+ break;
+ case PARITY_SPACE:
+ config |= (0x04 << 8);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown parity value: " + parity);
}
- if (amtWritten <= 0) {
- throw new IOException("Error writing " + writeLength
- + " bytes at offset " + offset + " length=" + src.length);
+ switch (stopBits) {
+ case STOPBITS_1:
+ config |= (0x00 << 11);
+ break;
+ case STOPBITS_1_5:
+ config |= (0x01 << 11);
+ break;
+ case STOPBITS_2:
+ config |= (0x02 << 11);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
- Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength);
- offset += amtWritten;
- }
- return offset;
- }
-
- private int setBaudRate(int baudRate) throws IOException {
- long[] vals = convertBaudrate(baudRate);
- long actualBaudrate = vals[0];
- long index = vals[1];
- long value = vals[2];
- int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
- SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index,
- null, 0, USB_WRITE_TIMEOUT_MILLIS);
- if (result != 0) {
- throw new IOException("Setting baudrate failed: result=" + result);
- }
- return (int) actualBaudrate;
- }
-
- @Override
- public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
- throws IOException {
- setBaudRate(baudRate);
-
- int config = dataBits;
-
- switch (parity) {
- case PARITY_NONE:
- config |= (0x00 << 8);
- break;
- case PARITY_ODD:
- config |= (0x01 << 8);
- break;
- case PARITY_EVEN:
- config |= (0x02 << 8);
- break;
- case PARITY_MARK:
- config |= (0x03 << 8);
- break;
- case PARITY_SPACE:
- config |= (0x04 << 8);
- break;
- default:
- throw new IllegalArgumentException("Unknown parity value: " + parity);
+ int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
+ SIO_SET_DATA_REQUEST, config, 0 /* index */,
+ null, 0, USB_WRITE_TIMEOUT_MILLIS);
+ if (result != 0) {
+ throw new IOException("Setting parameters failed: result=" + result);
+ }
}
- switch (stopBits) {
- case STOPBITS_1:
- config |= (0x00 << 11);
- break;
- case STOPBITS_1_5:
- config |= (0x01 << 11);
- break;
- case STOPBITS_2:
- config |= (0x02 << 11);
- break;
- default:
- throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
- }
+ private long[] convertBaudrate(int baudrate) {
+ // TODO(mikey): Braindead transcription of libfti method. Clean up,
+ // using more idiomatic Java where possible.
+ int divisor = 24000000 / baudrate;
+ int bestDivisor = 0;
+ int bestBaud = 0;
+ int bestBaudDiff = 0;
+ int fracCode[] = {
+ 0, 3, 2, 4, 1, 5, 6, 7
+ };
- int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
- SIO_SET_DATA_REQUEST, config, 0 /* index */,
- null, 0, USB_WRITE_TIMEOUT_MILLIS);
- if (result != 0) {
- throw new IOException("Setting parameters failed: result=" + result);
- }
- }
+ for (int i = 0; i < 2; i++) {
+ int tryDivisor = divisor + i;
+ int baudEstimate;
+ int baudDiff;
- private long[] convertBaudrate(int baudrate) {
- // TODO(mikey): Braindead transcription of libfti method. Clean up,
- // using more idiomatic Java where possible.
- int divisor = 24000000 / baudrate;
- int bestDivisor = 0;
- int bestBaud = 0;
- int bestBaudDiff = 0;
- int fracCode[] = {
- 0, 3, 2, 4, 1, 5, 6, 7
- };
-
- for (int i = 0; i < 2; i++) {
- int tryDivisor = divisor + i;
- int baudEstimate;
- int baudDiff;
-
- if (tryDivisor <= 8) {
- // Round up to minimum supported divisor
- tryDivisor = 8;
- } else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) {
- // BM doesn't support divisors 9 through 11 inclusive
- tryDivisor = 12;
- } else if (divisor < 16) {
- // AM doesn't support divisors 9 through 15 inclusive
- tryDivisor = 16;
- } else {
- if (mType == DeviceType.TYPE_AM) {
- // TODO
+ if (tryDivisor <= 8) {
+ // Round up to minimum supported divisor
+ tryDivisor = 8;
+ } else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) {
+ // BM doesn't support divisors 9 through 11 inclusive
+ tryDivisor = 12;
+ } else if (divisor < 16) {
+ // AM doesn't support divisors 9 through 15 inclusive
+ tryDivisor = 16;
} else {
- if (tryDivisor > 0x1FFFF) {
- // Round down to maximum supported divisor value (for
- // BM)
- tryDivisor = 0x1FFFF;
+ if (mType == DeviceType.TYPE_AM) {
+ // TODO
+ } else {
+ if (tryDivisor > 0x1FFFF) {
+ // Round down to maximum supported divisor value (for
+ // BM)
+ tryDivisor = 0x1FFFF;
+ }
+ }
+ }
+
+ // Get estimated baud rate (to nearest integer)
+ baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor;
+
+ // Get absolute difference from requested baud rate
+ if (baudEstimate < baudrate) {
+ baudDiff = baudrate - baudEstimate;
+ } else {
+ baudDiff = baudEstimate - baudrate;
+ }
+
+ if (i == 0 || baudDiff < bestBaudDiff) {
+ // Closest to requested baud rate so far
+ bestDivisor = tryDivisor;
+ bestBaud = baudEstimate;
+ bestBaudDiff = baudDiff;
+ if (baudDiff == 0) {
+ // Spot on! No point trying
+ break;
}
}
}
- // Get estimated baud rate (to nearest integer)
- baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor;
-
- // Get absolute difference from requested baud rate
- if (baudEstimate < baudrate) {
- baudDiff = baudrate - baudEstimate;
- } else {
- baudDiff = baudEstimate - baudrate;
+ // Encode the best divisor value
+ long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14);
+ // Deal with special cases for encoded value
+ if (encodedDivisor == 1) {
+ encodedDivisor = 0; // 3000000 baud
+ } else if (encodedDivisor == 0x4001) {
+ encodedDivisor = 1; // 2000000 baud (BM only)
}
- if (i == 0 || baudDiff < bestBaudDiff) {
- // Closest to requested baud rate so far
- bestDivisor = tryDivisor;
- bestBaud = baudEstimate;
- bestBaudDiff = baudDiff;
- if (baudDiff == 0) {
- // Spot on! No point trying
- break;
+ // Split into "value" and "index" values
+ long value = encodedDivisor & 0xFFFF;
+ long index;
+ if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
+ || mType == DeviceType.TYPE_4232H) {
+ index = (encodedDivisor >> 8) & 0xffff;
+ index &= 0xFF00;
+ index |= 0 /* TODO mIndex */;
+ } else {
+ index = (encodedDivisor >> 16) & 0xffff;
+ }
+
+ // Return the nearest baud rate
+ return new long[] {
+ bestBaud, index, value
+ };
+ }
+
+ @Override
+ public boolean getCD() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getCTS() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getDSR() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getDTR() throws IOException {
+ return false;
+ }
+
+ @Override
+ public void setDTR(boolean value) throws IOException {
+ }
+
+ @Override
+ public boolean getRI() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean getRTS() throws IOException {
+ return false;
+ }
+
+ @Override
+ public void setRTS(boolean value) throws IOException {
+ }
+
+ @Override
+ public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
+ if (purgeReadBuffers) {
+ int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
+ SIO_RESET_PURGE_RX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
+ if (result != 0) {
+ throw new IOException("Flushing RX failed: result=" + result);
}
}
- }
- // Encode the best divisor value
- long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14);
- // Deal with special cases for encoded value
- if (encodedDivisor == 1) {
- encodedDivisor = 0; // 3000000 baud
- } else if (encodedDivisor == 0x4001) {
- encodedDivisor = 1; // 2000000 baud (BM only)
- }
-
- // Split into "value" and "index" values
- long value = encodedDivisor & 0xFFFF;
- long index;
- if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
- || mType == DeviceType.TYPE_4232H) {
- index = (encodedDivisor >> 8) & 0xffff;
- index &= 0xFF00;
- index |= 0 /* TODO mIndex */;
- } else {
- index = (encodedDivisor >> 16) & 0xffff;
- }
-
- // Return the nearest baud rate
- return new long[] {
- bestBaud, index, value
- };
- }
-
- @Override
- public boolean getCD() throws IOException {
- return false;
- }
-
- @Override
- public boolean getCTS() throws IOException {
- return false;
- }
-
- @Override
- public boolean getDSR() throws IOException {
- return false;
- }
-
- @Override
- public boolean getDTR() throws IOException {
- return false;
- }
-
- @Override
- public void setDTR(boolean value) throws IOException {
- }
-
- @Override
- public boolean getRI() throws IOException {
- return false;
- }
-
- @Override
- public boolean getRTS() throws IOException {
- return false;
- }
-
- @Override
- public void setRTS(boolean value) throws IOException {
- }
-
- @Override
- public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
- if (purgeReadBuffers) {
- int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
- SIO_RESET_PURGE_RX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
- if (result != 0) {
- throw new IOException("Flushing RX failed: result=" + result);
+ if (purgeWriteBuffers) {
+ int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
+ SIO_RESET_PURGE_TX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
+ if (result != 0) {
+ throw new IOException("Flushing RX failed: result=" + result);
+ }
}
+ return true;
}
-
- if (purgeWriteBuffers) {
- int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
- SIO_RESET_PURGE_TX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
- if (result != 0) {
- throw new IOException("Flushing RX failed: result=" + result);
- }
- }
-
- return true;
}
public static Map getSupportedDevices() {
@@ -540,7 +572,7 @@ public class FtdiSerialDriver extends CommonUsbSerialDriver {
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
new int[] {
UsbId.FTDI_FT232R,
- UsbId.FTDI_FT231X,
+ UsbId.FTDI_FT231X,
});
return supportedDevices;
}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProbeTable.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProbeTable.java
new file mode 100644
index 0000000..db08019
--- /dev/null
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProbeTable.java
@@ -0,0 +1,108 @@
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
+ *
+ * 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: https://github.com/mik3y/usb-serial-for-android
+ */
+
+package com.hoho.android.usbserial.driver;
+
+import android.util.Pair;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Maps (vendor id, product id) pairs to the corresponding serial driver.
+ *
+ * @author mike wakerly (opensource@hoho.com)
+ */
+public class ProbeTable {
+
+ private final Map, Class extends UsbSerialDriver>> mProbeTable =
+ new LinkedHashMap, Class extends UsbSerialDriver>>();
+
+ /**
+ * Adds or updates a (vendor, product) pair in the table.
+ *
+ * @param vendorId the USB vendor id
+ * @param productId the USB product id
+ * @param driverClass the driver class responsible for this pair
+ * @return {@code this}, for chaining
+ */
+ public ProbeTable addProduct(int vendorId, int productId,
+ Class extends UsbSerialDriver> driverClass) {
+ mProbeTable.put(Pair.create(vendorId, productId), driverClass);
+ return this;
+ }
+
+ /**
+ * Internal method to add all supported products from
+ * {@code getSupportedProducts} static method.
+ *
+ * @param driverClass
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ ProbeTable addDriver(Class extends UsbSerialDriver> driverClass) {
+ final Method method;
+
+ try {
+ method = driverClass.getMethod("getSupportedDevices");
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+
+ final Map devices;
+ try {
+ devices = (Map) method.invoke(null);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+
+ for (Map.Entry entry : devices.entrySet()) {
+ final int vendorId = entry.getKey().intValue();
+ for (int productId : entry.getValue()) {
+ addProduct(vendorId, productId, driverClass);
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Returns the driver for the given (vendor, product) pair, or {@code null}
+ * if no match.
+ *
+ * @param vendorId the USB vendor id
+ * @param productId the USB product id
+ * @return the driver class matching this pair, or {@code null}
+ */
+ public Class extends UsbSerialDriver> findDriver(int vendorId, int productId) {
+ final Pair pair = Pair.create(vendorId, productId);
+ return mProbeTable.get(pair);
+ }
+
+}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
index 611498a..526f684 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
@@ -13,7 +13,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
/*
@@ -36,481 +36,515 @@ import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
+import java.util.Collections;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
-public class ProlificSerialDriver extends CommonUsbSerialDriver {
- private static final int USB_READ_TIMEOUT_MILLIS = 1000;
- private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
-
- private static final int USB_RECIP_INTERFACE = 0x01;
-
- private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01;
- private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01;
-
- private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
- | UsbConstants.USB_TYPE_VENDOR;
-
- private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN
- | UsbConstants.USB_TYPE_VENDOR;
-
- private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
- | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-
- private static final int WRITE_ENDPOINT = 0x02;
- private static final int READ_ENDPOINT = 0x83;
- private static final int INTERRUPT_ENDPOINT = 0x81;
-
- private static final int FLUSH_RX_REQUEST = 0x08;
- private static final int FLUSH_TX_REQUEST = 0x09;
-
- private static final int SET_LINE_REQUEST = 0x20;
- private static final int SET_CONTROL_REQUEST = 0x22;
-
- private static final int CONTROL_DTR = 0x01;
- private static final int CONTROL_RTS = 0x02;
-
- private static final int STATUS_FLAG_CD = 0x01;
- private static final int STATUS_FLAG_DSR = 0x02;
- private static final int STATUS_FLAG_RI = 0x08;
- private static final int STATUS_FLAG_CTS = 0x80;
-
- private static final int STATUS_BUFFER_SIZE = 10;
- private static final int STATUS_BYTE_IDX = 8;
-
- private static final int DEVICE_TYPE_HX = 0;
- private static final int DEVICE_TYPE_0 = 1;
- private static final int DEVICE_TYPE_1 = 2;
-
- private int mDeviceType = DEVICE_TYPE_HX;
-
- private UsbEndpoint mReadEndpoint;
- private UsbEndpoint mWriteEndpoint;
- private UsbEndpoint mInterruptEndpoint;
-
- private int mControlLinesValue = 0;
-
- private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1;
-
- private int mStatus = 0;
- private volatile Thread mReadStatusThread = null;
- private final Object mReadStatusThreadLock = new Object();
- boolean mStopReadStatusThread = false;
- private IOException mReadStatusException = null;
+public class ProlificSerialDriver implements UsbSerialDriver {
private final String TAG = ProlificSerialDriver.class.getSimpleName();
- private final byte[] inControlTransfer(int requestType, int request,
- int value, int index, int length) throws IOException {
- byte[] buffer = new byte[length];
- int result = mConnection.controlTransfer(requestType, request, value,
- index, buffer, length, USB_READ_TIMEOUT_MILLIS);
- if (result != length) {
- throw new IOException(
- String.format("ControlTransfer with value 0x%x failed: %d",
- value, result));
+ private final UsbDevice mDevice;
+ private final UsbSerialPort mPort;
+
+ public ProlificSerialDriver(UsbDevice device) {
+ mDevice = device;
+ mPort = new ProlificSerialPort(mDevice);
+ }
+
+ @Override
+ public List getPorts() {
+ return Collections.singletonList(mPort);
+ }
+
+ @Override
+ public UsbDevice getDevice() {
+ return mDevice;
+ }
+
+ class ProlificSerialPort extends CommonUsbSerialPort {
+
+ private static final int USB_READ_TIMEOUT_MILLIS = 1000;
+ private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
+
+ private static final int USB_RECIP_INTERFACE = 0x01;
+
+ private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01;
+ private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01;
+
+ private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
+ | UsbConstants.USB_TYPE_VENDOR;
+
+ private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN
+ | UsbConstants.USB_TYPE_VENDOR;
+
+ private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
+ | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+
+ private static final int WRITE_ENDPOINT = 0x02;
+ private static final int READ_ENDPOINT = 0x83;
+ private static final int INTERRUPT_ENDPOINT = 0x81;
+
+ private static final int FLUSH_RX_REQUEST = 0x08;
+ private static final int FLUSH_TX_REQUEST = 0x09;
+
+ private static final int SET_LINE_REQUEST = 0x20;
+ private static final int SET_CONTROL_REQUEST = 0x22;
+
+ private static final int CONTROL_DTR = 0x01;
+ private static final int CONTROL_RTS = 0x02;
+
+ private static final int STATUS_FLAG_CD = 0x01;
+ private static final int STATUS_FLAG_DSR = 0x02;
+ private static final int STATUS_FLAG_RI = 0x08;
+ private static final int STATUS_FLAG_CTS = 0x80;
+
+ private static final int STATUS_BUFFER_SIZE = 10;
+ private static final int STATUS_BYTE_IDX = 8;
+
+ private static final int DEVICE_TYPE_HX = 0;
+ private static final int DEVICE_TYPE_0 = 1;
+ private static final int DEVICE_TYPE_1 = 2;
+
+ private int mDeviceType = DEVICE_TYPE_HX;
+
+ private UsbEndpoint mReadEndpoint;
+ private UsbEndpoint mWriteEndpoint;
+ private UsbEndpoint mInterruptEndpoint;
+
+ private int mControlLinesValue = 0;
+
+ private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1;
+
+ private int mStatus = 0;
+ private volatile Thread mReadStatusThread = null;
+ private final Object mReadStatusThreadLock = new Object();
+ boolean mStopReadStatusThread = false;
+ private IOException mReadStatusException = null;
+
+
+ public ProlificSerialPort(UsbDevice device) {
+ super(device);
}
- return buffer;
- }
- private final void outControlTransfer(int requestType, int request,
- int value, int index, byte[] data) throws IOException {
- int length = (data == null) ? 0 : data.length;
- int result = mConnection.controlTransfer(requestType, request, value,
- index, data, length, USB_WRITE_TIMEOUT_MILLIS);
- if (result != length) {
- throw new IOException(
- String.format("ControlTransfer with value 0x%x failed: %d",
- value, result));
+ @Override
+ public UsbSerialDriver getDriver() {
+ return ProlificSerialDriver.this;
}
- }
- private final byte[] vendorIn(int value, int index, int length)
- throws IOException {
- return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE,
- PROLIFIC_VENDOR_READ_REQUEST, value, index, length);
- }
-
- private final void vendorOut(int value, int index, byte[] data)
- throws IOException {
- outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE,
- PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data);
- }
-
- private final void ctrlOut(int request, int value, int index, byte[] data)
- throws IOException {
- outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index,
- data);
- }
-
- private void doBlackMagic() throws IOException {
- vendorIn(0x8484, 0, 1);
- vendorOut(0x0404, 0, null);
- vendorIn(0x8484, 0, 1);
- vendorIn(0x8383, 0, 1);
- vendorIn(0x8484, 0, 1);
- vendorOut(0x0404, 1, null);
- vendorIn(0x8484, 0, 1);
- vendorIn(0x8383, 0, 1);
- vendorOut(0, 1, null);
- vendorOut(1, 0, null);
- vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null);
- }
-
- private void resetDevice() throws IOException {
- purgeHwBuffers(true, true);
- }
-
- private void setControlLines(int newControlLinesValue) throws IOException {
- ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null);
- mControlLinesValue = newControlLinesValue;
- }
-
- private final void readStatusThreadFunction() {
- try {
- while (!mStopReadStatusThread) {
- byte[] buffer = new byte[STATUS_BUFFER_SIZE];
- int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint,
- buffer,
- STATUS_BUFFER_SIZE,
- 500);
- if (readBytesCount > 0) {
- if (readBytesCount == STATUS_BUFFER_SIZE) {
- mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
- } else {
- throw new IOException(
- String.format("Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d",
- STATUS_BUFFER_SIZE,
- readBytesCount));
- }
- }
+ private final byte[] inControlTransfer(int requestType, int request,
+ int value, int index, int length) throws IOException {
+ byte[] buffer = new byte[length];
+ int result = mConnection.controlTransfer(requestType, request, value,
+ index, buffer, length, USB_READ_TIMEOUT_MILLIS);
+ if (result != length) {
+ throw new IOException(
+ String.format("ControlTransfer with value 0x%x failed: %d",
+ value, result));
}
- } catch (IOException e) {
- mReadStatusException = e;
+ return buffer;
}
- }
- private final int getStatus() throws IOException {
- if ((mReadStatusThread == null) && (mReadStatusException == null)) {
- synchronized (mReadStatusThreadLock) {
- if (mReadStatusThread == null) {
+ private final void outControlTransfer(int requestType, int request,
+ int value, int index, byte[] data) throws IOException {
+ int length = (data == null) ? 0 : data.length;
+ int result = mConnection.controlTransfer(requestType, request, value,
+ index, data, length, USB_WRITE_TIMEOUT_MILLIS);
+ if (result != length) {
+ throw new IOException(
+ String.format("ControlTransfer with value 0x%x failed: %d",
+ value, result));
+ }
+ }
+
+ private final byte[] vendorIn(int value, int index, int length)
+ throws IOException {
+ return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE,
+ PROLIFIC_VENDOR_READ_REQUEST, value, index, length);
+ }
+
+ private final void vendorOut(int value, int index, byte[] data)
+ throws IOException {
+ outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE,
+ PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data);
+ }
+
+ private void resetDevice() throws IOException {
+ purgeHwBuffers(true, true);
+ }
+
+ private final void ctrlOut(int request, int value, int index, byte[] data)
+ throws IOException {
+ outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index,
+ data);
+ }
+
+ private void doBlackMagic() throws IOException {
+ vendorIn(0x8484, 0, 1);
+ vendorOut(0x0404, 0, null);
+ vendorIn(0x8484, 0, 1);
+ vendorIn(0x8383, 0, 1);
+ vendorIn(0x8484, 0, 1);
+ vendorOut(0x0404, 1, null);
+ vendorIn(0x8484, 0, 1);
+ vendorIn(0x8383, 0, 1);
+ vendorOut(0, 1, null);
+ vendorOut(1, 0, null);
+ vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null);
+ }
+
+ private void setControlLines(int newControlLinesValue) throws IOException {
+ ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null);
+ mControlLinesValue = newControlLinesValue;
+ }
+
+ private final void readStatusThreadFunction() {
+ try {
+ while (!mStopReadStatusThread) {
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
- int readBytes = mConnection.bulkTransfer(mInterruptEndpoint,
+ int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint,
buffer,
STATUS_BUFFER_SIZE,
- 100);
- if (readBytes != STATUS_BUFFER_SIZE) {
- Log.w(TAG, "Could not read initial CTS / DSR / CD / RI status");
- } else {
- mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
- }
-
- mReadStatusThread = new Thread(new Runnable() {
- @Override
- public void run() {
- readStatusThreadFunction();
+ 500);
+ if (readBytesCount > 0) {
+ if (readBytesCount == STATUS_BUFFER_SIZE) {
+ mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
+ } else {
+ throw new IOException(
+ String.format("Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d",
+ STATUS_BUFFER_SIZE,
+ readBytesCount));
}
- });
- mReadStatusThread.setDaemon(true);
- mReadStatusThread.start();
- }
- }
- }
-
- /* throw and clear an exception which occured in the status read thread */
- IOException readStatusException = mReadStatusException;
- if (mReadStatusException != null) {
- mReadStatusException = null;
- throw readStatusException;
- }
-
- return mStatus;
- }
-
- private final boolean testStatusFlag(int flag) throws IOException {
- return ((getStatus() & flag) == flag);
- }
-
- public ProlificSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
- super(device, connection);
- }
-
- @Override
- public void open() throws IOException {
- UsbInterface usbInterface = mDevice.getInterface(0);
-
- if (!mConnection.claimInterface(usbInterface, true)) {
- throw new IOException("Error claiming Prolific interface 0");
- }
-
- boolean openSuccessful = false;
- try {
- for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {
- UsbEndpoint currentEndpoint = usbInterface.getEndpoint(i);
-
- switch (currentEndpoint.getAddress()) {
- case READ_ENDPOINT:
- mReadEndpoint = currentEndpoint;
- break;
-
- case WRITE_ENDPOINT:
- mWriteEndpoint = currentEndpoint;
- break;
-
- case INTERRUPT_ENDPOINT:
- mInterruptEndpoint = currentEndpoint;
- break;
- }
- }
-
- if (mDevice.getDeviceClass() == 0x02) {
- mDeviceType = DEVICE_TYPE_0;
- } else {
- try {
- Method getRawDescriptorsMethod
- = mConnection.getClass().getMethod("getRawDescriptors");
- byte[] rawDescriptors
- = (byte[]) getRawDescriptorsMethod.invoke(mConnection);
- byte maxPacketSize0 = rawDescriptors[7];
- if (maxPacketSize0 == 64) {
- mDeviceType = DEVICE_TYPE_HX;
- } else if ((mDevice.getDeviceClass() == 0x00)
- || (mDevice.getDeviceClass() == 0xff)) {
- mDeviceType = DEVICE_TYPE_1;
- } else {
- Log.w(TAG, "Could not detect PL2303 subtype, "
- + "Assuming that it is a HX device");
- mDeviceType = DEVICE_TYPE_HX;
}
- } catch (NoSuchMethodException e) {
- Log.w(TAG, "Method UsbDeviceConnection.getRawDescriptors, "
- + "required for PL2303 subtype detection, not "
- + "available! Assuming that it is a HX device");
- mDeviceType = DEVICE_TYPE_HX;
- } catch (Exception e) {
- Log.e(TAG, "An unexpected exception occured while trying "
- + "to detect PL2303 subtype", e);
}
- }
-
- setControlLines(mControlLinesValue);
- resetDevice();
-
- doBlackMagic();
- openSuccessful = true;
- } finally {
- if (!openSuccessful) {
- try {
- mConnection.releaseInterface(usbInterface);
- } catch (Exception ingored) {
- // Do not cover possible exceptions
- }
+ } catch (IOException e) {
+ mReadStatusException = e;
}
}
- }
- @Override
- public void close() throws IOException {
- try {
- mStopReadStatusThread = true;
- synchronized (mReadStatusThreadLock) {
- if (mReadStatusThread != null) {
- try {
- mReadStatusThread.join();
- } catch (Exception e) {
- Log.w(TAG, "An error occured while waiting for status read thread", e);
+ private final int getStatus() throws IOException {
+ if ((mReadStatusThread == null) && (mReadStatusException == null)) {
+ synchronized (mReadStatusThreadLock) {
+ if (mReadStatusThread == null) {
+ byte[] buffer = new byte[STATUS_BUFFER_SIZE];
+ int readBytes = mConnection.bulkTransfer(mInterruptEndpoint,
+ buffer,
+ STATUS_BUFFER_SIZE,
+ 100);
+ if (readBytes != STATUS_BUFFER_SIZE) {
+ Log.w(TAG, "Could not read initial CTS / DSR / CD / RI status");
+ } else {
+ mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
+ }
+
+ mReadStatusThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ readStatusThreadFunction();
+ }
+ });
+ mReadStatusThread.setDaemon(true);
+ mReadStatusThread.start();
}
}
}
- resetDevice();
- } finally {
- mConnection.releaseInterface(mDevice.getInterface(0));
- }
- }
-
- @Override
- public int read(byte[] dest, int timeoutMillis) throws IOException {
- synchronized (mReadBufferLock) {
- int readAmt = Math.min(dest.length, mReadBuffer.length);
- int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,
- readAmt, timeoutMillis);
- if (numBytesRead < 0) {
- return 0;
+ /* throw and clear an exception which occured in the status read thread */
+ IOException readStatusException = mReadStatusException;
+ if (mReadStatusException != null) {
+ mReadStatusException = null;
+ throw readStatusException;
}
- System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
- return numBytesRead;
+
+ return mStatus;
}
- }
- @Override
- public int write(byte[] src, int timeoutMillis) throws IOException {
- int offset = 0;
+ private final boolean testStatusFlag(int flag) throws IOException {
+ return ((getStatus() & flag) == flag);
+ }
- while (offset < src.length) {
- final int writeLength;
- final int amtWritten;
+ @Override
+ public void open(UsbDeviceConnection connection) throws IOException {
+ if (mConnection != null) {
+ throw new IOException("Already open");
+ }
- synchronized (mWriteBufferLock) {
- final byte[] writeBuffer;
+ UsbInterface usbInterface = mDevice.getInterface(0);
- writeLength = Math.min(src.length - offset, mWriteBuffer.length);
- if (offset == 0) {
- writeBuffer = src;
+ if (!connection.claimInterface(usbInterface, true)) {
+ throw new IOException("Error claiming Prolific interface 0");
+ }
+
+ mConnection = connection;
+ boolean opened = false;
+ try {
+ for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {
+ UsbEndpoint currentEndpoint = usbInterface.getEndpoint(i);
+
+ switch (currentEndpoint.getAddress()) {
+ case READ_ENDPOINT:
+ mReadEndpoint = currentEndpoint;
+ break;
+
+ case WRITE_ENDPOINT:
+ mWriteEndpoint = currentEndpoint;
+ break;
+
+ case INTERRUPT_ENDPOINT:
+ mInterruptEndpoint = currentEndpoint;
+ break;
+ }
+ }
+
+ if (mDevice.getDeviceClass() == 0x02) {
+ mDeviceType = DEVICE_TYPE_0;
} else {
- // bulkTransfer does not support offsets, make a copy.
- System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
- writeBuffer = mWriteBuffer;
+ try {
+ Method getRawDescriptorsMethod
+ = mConnection.getClass().getMethod("getRawDescriptors");
+ byte[] rawDescriptors
+ = (byte[]) getRawDescriptorsMethod.invoke(mConnection);
+ byte maxPacketSize0 = rawDescriptors[7];
+ if (maxPacketSize0 == 64) {
+ mDeviceType = DEVICE_TYPE_HX;
+ } else if ((mDevice.getDeviceClass() == 0x00)
+ || (mDevice.getDeviceClass() == 0xff)) {
+ mDeviceType = DEVICE_TYPE_1;
+ } else {
+ Log.w(TAG, "Could not detect PL2303 subtype, "
+ + "Assuming that it is a HX device");
+ mDeviceType = DEVICE_TYPE_HX;
+ }
+ } catch (NoSuchMethodException e) {
+ Log.w(TAG, "Method UsbDeviceConnection.getRawDescriptors, "
+ + "required for PL2303 subtype detection, not "
+ + "available! Assuming that it is a HX device");
+ mDeviceType = DEVICE_TYPE_HX;
+ } catch (Exception e) {
+ Log.e(TAG, "An unexpected exception occured while trying "
+ + "to detect PL2303 subtype", e);
+ }
}
- amtWritten = mConnection.bulkTransfer(mWriteEndpoint,
- writeBuffer, writeLength, timeoutMillis);
+ setControlLines(mControlLinesValue);
+ resetDevice();
+
+ doBlackMagic();
+ opened = true;
+ } finally {
+ if (!opened) {
+ mConnection = null;
+ connection.releaseInterface(usbInterface);
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (mConnection == null) {
+ throw new IOException("Already closed");
+ }
+ try {
+ mStopReadStatusThread = true;
+ synchronized (mReadStatusThreadLock) {
+ if (mReadStatusThread != null) {
+ try {
+ mReadStatusThread.join();
+ } catch (Exception e) {
+ Log.w(TAG, "An error occured while waiting for status read thread", e);
+ }
+ }
+ }
+ resetDevice();
+ } finally {
+ try {
+ mConnection.releaseInterface(mDevice.getInterface(0));
+ } finally {
+ mConnection = null;
+ }
+ }
+ }
+
+ @Override
+ public int read(byte[] dest, int timeoutMillis) throws IOException {
+ synchronized (mReadBufferLock) {
+ int readAmt = Math.min(dest.length, mReadBuffer.length);
+ int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,
+ readAmt, timeoutMillis);
+ if (numBytesRead < 0) {
+ return 0;
+ }
+ System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
+ return numBytesRead;
+ }
+ }
+
+ @Override
+ public int write(byte[] src, int timeoutMillis) throws IOException {
+ int offset = 0;
+
+ while (offset < src.length) {
+ final int writeLength;
+ final int amtWritten;
+
+ synchronized (mWriteBufferLock) {
+ final byte[] writeBuffer;
+
+ writeLength = Math.min(src.length - offset, mWriteBuffer.length);
+ if (offset == 0) {
+ writeBuffer = src;
+ } else {
+ // bulkTransfer does not support offsets, make a copy.
+ System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
+ writeBuffer = mWriteBuffer;
+ }
+
+ amtWritten = mConnection.bulkTransfer(mWriteEndpoint,
+ writeBuffer, writeLength, timeoutMillis);
+ }
+
+ if (amtWritten <= 0) {
+ throw new IOException("Error writing " + writeLength
+ + " bytes at offset " + offset + " length="
+ + src.length);
+ }
+
+ offset += amtWritten;
+ }
+ return offset;
+ }
+
+ @Override
+ public void setParameters(int baudRate, int dataBits, int stopBits,
+ int parity) throws IOException {
+ if ((mBaudRate == baudRate) && (mDataBits == dataBits)
+ && (mStopBits == stopBits) && (mParity == parity)) {
+ // Make sure no action is performed if there is nothing to change
+ return;
}
- if (amtWritten <= 0) {
- throw new IOException("Error writing " + writeLength
- + " bytes at offset " + offset + " length="
- + src.length);
+ byte[] lineRequestData = new byte[7];
+
+ lineRequestData[0] = (byte) (baudRate & 0xff);
+ lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff);
+ lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff);
+ lineRequestData[3] = (byte) ((baudRate >> 24) & 0xff);
+
+ switch (stopBits) {
+ case STOPBITS_1:
+ lineRequestData[4] = 0;
+ break;
+
+ case STOPBITS_1_5:
+ lineRequestData[4] = 1;
+ break;
+
+ case STOPBITS_2:
+ lineRequestData[4] = 2;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
- offset += amtWritten;
- }
- return offset;
- }
+ switch (parity) {
+ case PARITY_NONE:
+ lineRequestData[5] = 0;
+ break;
- @Override
- public void setParameters(int baudRate, int dataBits, int stopBits,
- int parity) throws IOException {
- if ((mBaudRate == baudRate) && (mDataBits == dataBits)
- && (mStopBits == stopBits) && (mParity == parity)) {
- // Make sure no action is performed if there is nothing to change
- return;
+ case PARITY_ODD:
+ lineRequestData[5] = 1;
+ break;
+
+ case PARITY_MARK:
+ lineRequestData[5] = 3;
+ break;
+
+ case PARITY_SPACE:
+ lineRequestData[5] = 4;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown parity value: " + parity);
+ }
+
+ lineRequestData[6] = (byte) dataBits;
+
+ ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData);
+
+ resetDevice();
+
+ mBaudRate = baudRate;
+ mDataBits = dataBits;
+ mStopBits = stopBits;
+ mParity = parity;
}
- byte[] lineRequestData = new byte[7];
-
- lineRequestData[0] = (byte) (baudRate & 0xff);
- lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff);
- lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff);
- lineRequestData[3] = (byte) ((baudRate >> 24) & 0xff);
-
- switch (stopBits) {
- case STOPBITS_1:
- lineRequestData[4] = 0;
- break;
-
- case STOPBITS_1_5:
- lineRequestData[4] = 1;
- break;
-
- case STOPBITS_2:
- lineRequestData[4] = 2;
- break;
-
- default:
- throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
+ @Override
+ public boolean getCD() throws IOException {
+ return testStatusFlag(STATUS_FLAG_CD);
}
- switch (parity) {
- case PARITY_NONE:
- lineRequestData[5] = 0;
- break;
-
- case PARITY_ODD:
- lineRequestData[5] = 1;
- break;
-
- case PARITY_EVEN:
- lineRequestData[5] = 2;
- break;
-
- case PARITY_MARK:
- lineRequestData[5] = 3;
- break;
-
- case PARITY_SPACE:
- lineRequestData[5] = 4;
- break;
-
- default:
- throw new IllegalArgumentException("Unknown parity value: " + parity);
+ @Override
+ public boolean getCTS() throws IOException {
+ return testStatusFlag(STATUS_FLAG_CTS);
}
- lineRequestData[6] = (byte) dataBits;
-
- ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData);
-
- resetDevice();
-
- mBaudRate = baudRate;
- mDataBits = dataBits;
- mStopBits = stopBits;
- mParity = parity;
- }
-
- @Override
- public boolean getCD() throws IOException {
- return testStatusFlag(STATUS_FLAG_CD);
- }
-
- @Override
- public boolean getCTS() throws IOException {
- return testStatusFlag(STATUS_FLAG_CTS);
- }
-
- @Override
- public boolean getDSR() throws IOException {
- return testStatusFlag(STATUS_FLAG_DSR);
- }
-
- @Override
- public boolean getDTR() throws IOException {
- return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR);
- }
-
- @Override
- public void setDTR(boolean value) throws IOException {
- int newControlLinesValue;
- if (value) {
- newControlLinesValue = mControlLinesValue | CONTROL_DTR;
- } else {
- newControlLinesValue = mControlLinesValue & ~CONTROL_DTR;
- }
- setControlLines(newControlLinesValue);
- }
-
- @Override
- public boolean getRI() throws IOException {
- return testStatusFlag(STATUS_FLAG_RI);
- }
-
- @Override
- public boolean getRTS() throws IOException {
- return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS);
- }
-
- @Override
- public void setRTS(boolean value) throws IOException {
- int newControlLinesValue;
- if (value) {
- newControlLinesValue = mControlLinesValue | CONTROL_RTS;
- } else {
- newControlLinesValue = mControlLinesValue & ~CONTROL_RTS;
- }
- setControlLines(newControlLinesValue);
- }
-
- @Override
- public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
- if (purgeReadBuffers) {
- vendorOut(FLUSH_RX_REQUEST, 0, null);
+ @Override
+ public boolean getDSR() throws IOException {
+ return testStatusFlag(STATUS_FLAG_DSR);
}
- if (purgeWriteBuffers) {
- vendorOut(FLUSH_TX_REQUEST, 0, null);
+ @Override
+ public boolean getDTR() throws IOException {
+ return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR);
}
- return true;
+ @Override
+ public void setDTR(boolean value) throws IOException {
+ int newControlLinesValue;
+ if (value) {
+ newControlLinesValue = mControlLinesValue | CONTROL_DTR;
+ } else {
+ newControlLinesValue = mControlLinesValue & ~CONTROL_DTR;
+ }
+ setControlLines(newControlLinesValue);
+ }
+
+ @Override
+ public boolean getRI() throws IOException {
+ return testStatusFlag(STATUS_FLAG_RI);
+ }
+
+ @Override
+ public boolean getRTS() throws IOException {
+ return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS);
+ }
+
+ @Override
+ public void setRTS(boolean value) throws IOException {
+ int newControlLinesValue;
+ if (value) {
+ newControlLinesValue = mControlLinesValue | CONTROL_RTS;
+ } else {
+ newControlLinesValue = mControlLinesValue & ~CONTROL_RTS;
+ }
+ setControlLines(newControlLinesValue);
+ }
+
+ @Override
+ public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
+ if (purgeReadBuffers) {
+ vendorOut(FLUSH_RX_REQUEST, 0, null);
+ }
+
+ if (purgeWriteBuffers) {
+ vendorOut(FLUSH_TX_REQUEST, 0, null);
+ }
+
+ return purgeReadBuffers || purgeWriteBuffers;
+ }
}
public static Map getSupportedDevices() {
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
index 2b228aa..b837c8a 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
@@ -1,4 +1,5 @@
-/* Copyright 2012 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,8 +16,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
+
package com.hoho.android.usbserial.driver;
/**
@@ -52,7 +54,7 @@ public final class UsbId {
public static final int VENDOR_LEAFLABS = 0x1eaf;
public static final int LEAFLABS_MAPLE = 0x0004;
-
+
public static final int VENDOR_SILAB = 0x10c4;
public static final int SILAB_CP2102 = 0xea60;
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
index d70712d..9130d97 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
@@ -1,4 +1,5 @@
-/* Copyright 2011 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,196 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.driver;
-import java.io.IOException;
+import android.hardware.usb.UsbDevice;
+
+import java.util.List;
/**
- * Driver interface for a USB serial device.
*
* @author mike wakerly (opensource@hoho.com)
*/
public interface UsbSerialDriver {
- /** 5 data bits. */
- public static final int DATABITS_5 = 5;
-
- /** 6 data bits. */
- public static final int DATABITS_6 = 6;
-
- /** 7 data bits. */
- public static final int DATABITS_7 = 7;
-
- /** 8 data bits. */
- public static final int DATABITS_8 = 8;
-
- /** No flow control. */
- public static final int FLOWCONTROL_NONE = 0;
-
- /** RTS/CTS input flow control. */
- public static final int FLOWCONTROL_RTSCTS_IN = 1;
-
- /** RTS/CTS output flow control. */
- public static final int FLOWCONTROL_RTSCTS_OUT = 2;
-
- /** XON/XOFF input flow control. */
- public static final int FLOWCONTROL_XONXOFF_IN = 4;
-
- /** XON/XOFF output flow control. */
- public static final int FLOWCONTROL_XONXOFF_OUT = 8;
-
- /** No parity. */
- public static final int PARITY_NONE = 0;
-
- /** Odd parity. */
- public static final int PARITY_ODD = 1;
-
- /** Even parity. */
- public static final int PARITY_EVEN = 2;
-
- /** Mark parity. */
- public static final int PARITY_MARK = 3;
-
- /** Space parity. */
- public static final int PARITY_SPACE = 4;
-
- /** 1 stop bit. */
- public static final int STOPBITS_1 = 1;
-
- /** 1.5 stop bits. */
- public static final int STOPBITS_1_5 = 3;
-
- /** 2 stop bits. */
- public static final int STOPBITS_2 = 2;
-
/**
- * Opens and initializes the device as a USB serial device. Upon success,
- * caller must ensure that {@link #close()} is eventually called.
+ * Returns the raw {@link UsbDevice} backing this port.
*
- * @throws IOException on error opening or initializing the device.
+ * @return the device
*/
- public void open() throws IOException;
+ public UsbDevice getDevice();
/**
- * Closes the serial device.
+ * Returns all available ports for this device. This list must have at least
+ * one entry.
*
- * @throws IOException on error closing the device.
+ * @return the ports
*/
- public void close() throws IOException;
-
- /**
- * Reads as many bytes as possible into the destination buffer.
- *
- * @param dest the destination byte buffer
- * @param timeoutMillis the timeout for reading
- * @return the actual number of bytes read
- * @throws IOException if an error occurred during reading
- */
- public int read(final byte[] dest, final int timeoutMillis) throws IOException;
-
- /**
- * Writes as many bytes as possible from the source buffer.
- *
- * @param src the source byte buffer
- * @param timeoutMillis the timeout for writing
- * @return the actual number of bytes written
- * @throws IOException if an error occurred during writing
- */
- public int write(final byte[] src, final int timeoutMillis) throws IOException;
-
- /**
- * Sets various serial port parameters.
- *
- * @param baudRate baud rate as an integer, for example {@code 115200}.
- * @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6},
- * {@link #DATABITS_7}, or {@link #DATABITS_8}.
- * @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or
- * {@link #STOPBITS_2}.
- * @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD},
- * {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or
- * {@link #PARITY_SPACE}.
- * @throws IOException on error setting the port parameters
- */
- public void setParameters(
- int baudRate, int dataBits, int stopBits, int parity) throws IOException;
-
- /**
- * Gets the CD (Carrier Detect) bit from the underlying UART.
- *
- * @return the current state, or {@code false} if not supported.
- * @throws IOException if an error occurred during reading
- */
- public boolean getCD() throws IOException;
-
- /**
- * Gets the CTS (Clear To Send) bit from the underlying UART.
- *
- * @return the current state, or {@code false} if not supported.
- * @throws IOException if an error occurred during reading
- */
- public boolean getCTS() throws IOException;
-
- /**
- * Gets the DSR (Data Set Ready) bit from the underlying UART.
- *
- * @return the current state, or {@code false} if not supported.
- * @throws IOException if an error occurred during reading
- */
- public boolean getDSR() throws IOException;
-
- /**
- * Gets the DTR (Data Terminal Ready) bit from the underlying UART.
- *
- * @return the current state, or {@code false} if not supported.
- * @throws IOException if an error occurred during reading
- */
- public boolean getDTR() throws IOException;
-
- /**
- * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if
- * supported.
- *
- * @param value the value to set
- * @throws IOException if an error occurred during writing
- */
- public void setDTR(boolean value) throws IOException;
-
- /**
- * Gets the RI (Ring Indicator) bit from the underlying UART.
- *
- * @return the current state, or {@code false} if not supported.
- * @throws IOException if an error occurred during reading
- */
- public boolean getRI() throws IOException;
-
- /**
- * Gets the RTS (Request To Send) bit from the underlying UART.
- *
- * @return the current state, or {@code false} if not supported.
- * @throws IOException if an error occurred during reading
- */
- public boolean getRTS() throws IOException;
-
- /**
- * Sets the RTS (Request To Send) bit on the underlying UART, if
- * supported.
- *
- * @param value the value to set
- * @throws IOException if an error occurred during writing
- */
- public void setRTS(boolean value) throws IOException;
-
- /**
- * Flush non-transmitted output data and / or non-read input data
- * @param flushRX {@code true} to flush non-transmitted output data
- * @param flushTX {@code true} to flush non-read input data
- * @return {@code true} if the operation was successful, or
- * {@code false} if the operation is not supported by the driver or device
- * @throws IOException if an error occurred during flush
- */
- public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException;
-
+ public List getPorts();
}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java
new file mode 100644
index 0000000..3cd0080
--- /dev/null
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java
@@ -0,0 +1,218 @@
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
+ *
+ * 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: https://github.com/mik3y/usb-serial-for-android
+ */
+
+package com.hoho.android.usbserial.driver;
+
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
+
+import java.io.IOException;
+
+/**
+ * Interface for a single serial port.
+ *
+ * @author mike wakerly (opensource@hoho.com)
+ */
+public interface UsbSerialPort {
+
+ /** 5 data bits. */
+ public static final int DATABITS_5 = 5;
+
+ /** 6 data bits. */
+ public static final int DATABITS_6 = 6;
+
+ /** 7 data bits. */
+ public static final int DATABITS_7 = 7;
+
+ /** 8 data bits. */
+ public static final int DATABITS_8 = 8;
+
+ /** No flow control. */
+ public static final int FLOWCONTROL_NONE = 0;
+
+ /** RTS/CTS input flow control. */
+ public static final int FLOWCONTROL_RTSCTS_IN = 1;
+
+ /** RTS/CTS output flow control. */
+ public static final int FLOWCONTROL_RTSCTS_OUT = 2;
+
+ /** XON/XOFF input flow control. */
+ public static final int FLOWCONTROL_XONXOFF_IN = 4;
+
+ /** XON/XOFF output flow control. */
+ public static final int FLOWCONTROL_XONXOFF_OUT = 8;
+
+ /** No parity. */
+ public static final int PARITY_NONE = 0;
+
+ /** Odd parity. */
+ public static final int PARITY_ODD = 1;
+
+ /** Even parity. */
+ public static final int PARITY_EVEN = 2;
+
+ /** Mark parity. */
+ public static final int PARITY_MARK = 3;
+
+ /** Space parity. */
+ public static final int PARITY_SPACE = 4;
+
+ /** 1 stop bit. */
+ public static final int STOPBITS_1 = 1;
+
+ /** 1.5 stop bits. */
+ public static final int STOPBITS_1_5 = 3;
+
+ /** 2 stop bits. */
+ public static final int STOPBITS_2 = 2;
+
+ public UsbSerialDriver getDriver();
+
+ /**
+ * Opens and initializes the port. Upon success, caller must ensure that
+ * {@link #close()} is eventually called.
+ *
+ * @param connection an open device connection, acquired with
+ * {@link UsbManager#openDevice(android.hardware.usb.UsbDevice)}
+ * @throws IOException on error opening or initializing the port.
+ */
+ public void open(UsbDeviceConnection connection) throws IOException;
+
+ /**
+ * Closes the port.
+ *
+ * @throws IOException on error closing the port.
+ */
+ public void close() throws IOException;
+
+ /**
+ * Reads as many bytes as possible into the destination buffer.
+ *
+ * @param dest the destination byte buffer
+ * @param timeoutMillis the timeout for reading
+ * @return the actual number of bytes read
+ * @throws IOException if an error occurred during reading
+ */
+ public int read(final byte[] dest, final int timeoutMillis) throws IOException;
+
+ /**
+ * Writes as many bytes as possible from the source buffer.
+ *
+ * @param src the source byte buffer
+ * @param timeoutMillis the timeout for writing
+ * @return the actual number of bytes written
+ * @throws IOException if an error occurred during writing
+ */
+ public int write(final byte[] src, final int timeoutMillis) throws IOException;
+
+ /**
+ * Sets various serial port parameters.
+ *
+ * @param baudRate baud rate as an integer, for example {@code 115200}.
+ * @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6},
+ * {@link #DATABITS_7}, or {@link #DATABITS_8}.
+ * @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or
+ * {@link #STOPBITS_2}.
+ * @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD},
+ * {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or
+ * {@link #PARITY_SPACE}.
+ * @throws IOException on error setting the port parameters
+ */
+ public void setParameters(
+ int baudRate, int dataBits, int stopBits, int parity) throws IOException;
+
+ /**
+ * Gets the CD (Carrier Detect) bit from the underlying UART.
+ *
+ * @return the current state, or {@code false} if not supported.
+ * @throws IOException if an error occurred during reading
+ */
+ public boolean getCD() throws IOException;
+
+ /**
+ * Gets the CTS (Clear To Send) bit from the underlying UART.
+ *
+ * @return the current state, or {@code false} if not supported.
+ * @throws IOException if an error occurred during reading
+ */
+ public boolean getCTS() throws IOException;
+
+ /**
+ * Gets the DSR (Data Set Ready) bit from the underlying UART.
+ *
+ * @return the current state, or {@code false} if not supported.
+ * @throws IOException if an error occurred during reading
+ */
+ public boolean getDSR() throws IOException;
+
+ /**
+ * Gets the DTR (Data Terminal Ready) bit from the underlying UART.
+ *
+ * @return the current state, or {@code false} if not supported.
+ * @throws IOException if an error occurred during reading
+ */
+ public boolean getDTR() throws IOException;
+
+ /**
+ * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if
+ * supported.
+ *
+ * @param value the value to set
+ * @throws IOException if an error occurred during writing
+ */
+ public void setDTR(boolean value) throws IOException;
+
+ /**
+ * Gets the RI (Ring Indicator) bit from the underlying UART.
+ *
+ * @return the current state, or {@code false} if not supported.
+ * @throws IOException if an error occurred during reading
+ */
+ public boolean getRI() throws IOException;
+
+ /**
+ * Gets the RTS (Request To Send) bit from the underlying UART.
+ *
+ * @return the current state, or {@code false} if not supported.
+ * @throws IOException if an error occurred during reading
+ */
+ public boolean getRTS() throws IOException;
+
+ /**
+ * Sets the RTS (Request To Send) bit on the underlying UART, if
+ * supported.
+ *
+ * @param value the value to set
+ * @throws IOException if an error occurred during writing
+ */
+ public void setRTS(boolean value) throws IOException;
+
+ /**
+ * Flush non-transmitted output data and / or non-read input data
+ * @param flushRX {@code true} to flush non-transmitted output data
+ * @param flushTX {@code true} to flush non-read input data
+ * @return {@code true} if the operation was successful, or
+ * {@code false} if the operation is not supported by the driver or device
+ * @throws IOException if an error occurred during flush
+ */
+ public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException;
+
+}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
index 420a8c2..d00bf63 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
@@ -1,4 +1,5 @@
-/* Copyright 2011 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,233 +16,79 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
/**
- * Helper class which finds compatible {@link UsbDevice}s and creates
- * {@link UsbSerialDriver} instances.
- *
- *
- * You don't need a Prober to use the rest of the library: it is perfectly
- * acceptable to instantiate driver instances manually. The Prober simply
- * provides convenience functions.
- *
- *
- * For most drivers, the corresponding {@link #probe(UsbManager, UsbDevice)}
- * method will either return an empty list (device unknown / unsupported) or a
- * singleton list. However, multi-port drivers may return multiple instances.
*
* @author mike wakerly (opensource@hoho.com)
*/
-public enum UsbSerialProber {
+public class UsbSerialProber {
- // TODO(mikey): Too much boilerplate.
+ private final ProbeTable mProbeTable;
+
+ public UsbSerialProber(ProbeTable probeTable) {
+ mProbeTable = probeTable;
+ }
+
+ public static UsbSerialProber getDefaultProber() {
+ final ProbeTable probeTable = new ProbeTable();
+ probeTable.addDriver(CdcAcmSerialDriver.class);
+ probeTable.addDriver(Cp2102SerialDriver.class);
+ probeTable.addDriver(FtdiSerialDriver.class);
+ probeTable.addDriver(ProlificSerialDriver.class);
+ return new UsbSerialProber(probeTable);
+ }
/**
- * Prober for {@link FtdiSerialDriver}.
+ * Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers}
+ * from the currently-attached {@link UsbDevice} hierarchy. This method does
+ * not require permission from the Android USB system, since it does not
+ * open any of the devices.
*
- * @see FtdiSerialDriver
+ * @param usbManager
+ * @return a list, possibly empty, of all compatible drivers
*/
- FTDI_SERIAL {
- @Override
- public List probe(final UsbManager manager, final UsbDevice usbDevice) {
- if (!testIfSupported(usbDevice, FtdiSerialDriver.getSupportedDevices())) {
- return Collections.emptyList();
- }
- final UsbDeviceConnection connection = manager.openDevice(usbDevice);
- if (connection == null) {
- return Collections.emptyList();
- }
- final UsbSerialDriver driver = new FtdiSerialDriver(usbDevice, connection);
- return Collections.singletonList(driver);
- }
- },
+ public List findAllDrivers(final UsbManager usbManager) {
+ final List result = new ArrayList();
- CDC_ACM_SERIAL {
- @Override
- public List probe(UsbManager manager, UsbDevice usbDevice) {
- if (!testIfSupported(usbDevice, CdcAcmSerialDriver.getSupportedDevices())) {
- return Collections.emptyList();
- }
- final UsbDeviceConnection connection = manager.openDevice(usbDevice);
- if (connection == null) {
- return Collections.emptyList();
- }
- final UsbSerialDriver driver = new CdcAcmSerialDriver(usbDevice, connection);
- return Collections.singletonList(driver);
- }
- },
-
- SILAB_SERIAL {
- @Override
- public List probe(final UsbManager manager, final UsbDevice usbDevice) {
- if (!testIfSupported(usbDevice, Cp2102SerialDriver.getSupportedDevices())) {
- return Collections.emptyList();
- }
- final UsbDeviceConnection connection = manager.openDevice(usbDevice);
- if (connection == null) {
- return Collections.emptyList();
- }
- final UsbSerialDriver driver = new Cp2102SerialDriver(usbDevice, connection);
- return Collections.singletonList(driver);
- }
- },
-
- PROLIFIC_SERIAL {
- @Override
- public List probe(final UsbManager manager, final UsbDevice usbDevice) {
- if (!testIfSupported(usbDevice, ProlificSerialDriver.getSupportedDevices())) {
- return Collections.emptyList();
- }
- final UsbDeviceConnection connection = manager.openDevice(usbDevice);
- if (connection == null) {
- return Collections.emptyList();
- }
- final UsbSerialDriver driver = new ProlificSerialDriver(usbDevice, connection);
- return Collections.singletonList(driver);
- }
- };
-
- /**
- * Tests the supplied {@link UsbDevice} for compatibility with this enum
- * member, returning one or more driver instances if compatible.
- *
- * @param manager the {@link UsbManager} to use
- * @param usbDevice the raw {@link UsbDevice} to use
- * @return zero or more {@link UsbSerialDriver}, depending on compatibility
- * (never {@code null}).
- */
- protected abstract List probe(final UsbManager manager, final UsbDevice usbDevice);
-
- /**
- * Creates and returns a new {@link UsbSerialDriver} instance for the first
- * compatible {@link UsbDevice} found on the bus. If none are found,
- * returns {@code null}.
- *
- *
- * The order of devices is undefined, therefore if there are multiple
- * devices on the bus, the chosen device may not be predictable (clients
- * should use {@link #findAllDevices(UsbManager)} instead).
- *
- * @param usbManager the {@link UsbManager} to use.
- * @return the first available {@link UsbSerialDriver}, or {@code null} if
- * none are available.
- */
- public static UsbSerialDriver findFirstDevice(final UsbManager usbManager) {
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
- for (final UsbSerialProber prober : values()) {
- final List probedDevices = prober.probe(usbManager, usbDevice);
- if (!probedDevices.isEmpty()) {
- return probedDevices.get(0);
+ final int vendorId = usbDevice.getVendorId();
+ final int productId = usbDevice.getProductId();
+
+ final Class extends UsbSerialDriver> driverClass =
+ mProbeTable.findDriver(vendorId, productId);
+ if (driverClass != null) {
+ final UsbSerialDriver driver;
+ try {
+ final Constructor extends UsbSerialDriver> ctor =
+ driverClass.getConstructor(UsbDevice.class);
+ driver = ctor.newInstance(usbDevice);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
}
+ result.add(driver);
}
}
- return null;
- }
-
- /**
- * Creates a new {@link UsbSerialDriver} instance for all compatible
- * {@link UsbDevice}s found on the bus. If no compatible devices are found,
- * the list will be empty.
- *
- * @param usbManager
- * @return
- */
- public static List findAllDevices(final UsbManager usbManager) {
- final List result = new ArrayList();
-
- // For each UsbDevice, call probe() for each prober.
- for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
- result.addAll(probeSingleDevice(usbManager, usbDevice));
- }
return result;
}
- /**
- * Special method for testing a specific device for driver support,
- * returning any compatible driver(s).
- *
- *
- * Clients should ordinarily use {@link #findAllDevices(UsbManager)}, which
- * operates against the entire bus of devices. This method is useful when
- * testing against only a single target is desired.
- *
- * @param usbManager the {@link UsbManager} to use.
- * @param usbDevice the device to test against.
- * @return a list containing zero or more {@link UsbSerialDriver} instances.
- */
- public static List probeSingleDevice(final UsbManager usbManager,
- UsbDevice usbDevice) {
- final List result = new ArrayList();
- for (final UsbSerialProber prober : values()) {
- final List probedDevices = prober.probe(usbManager, usbDevice);
- result.addAll(probedDevices);
- }
- return result;
- }
-
- /**
- * Deprecated; Use {@link #findFirstDevice(UsbManager)}.
- *
- * @param usbManager
- * @return
- */
- @Deprecated
- public static UsbSerialDriver acquire(final UsbManager usbManager) {
- return findFirstDevice(usbManager);
- }
-
- /**
- * Deprecated; use {@link #probeSingleDevice(UsbManager, UsbDevice)}.
- *
- * @param usbManager
- * @param usbDevice
- * @return
- */
- @Deprecated
- public static UsbSerialDriver acquire(final UsbManager usbManager, final UsbDevice usbDevice) {
- final List probedDevices = probeSingleDevice(usbManager, usbDevice);
- if (!probedDevices.isEmpty()) {
- return probedDevices.get(0);
- }
- return null;
- }
-
- /**
- * Returns {@code true} if the given device is found in the driver's
- * vendor/product map.
- *
- * @param usbDevice the device to test
- * @param supportedDevices map of vendor IDs to product ID(s)
- * @return {@code true} if supported
- */
- private static boolean testIfSupported(final UsbDevice usbDevice,
- final Map supportedDevices) {
- final int[] supportedProducts = supportedDevices.get(
- Integer.valueOf(usbDevice.getVendorId()));
- if (supportedProducts == null) {
- return false;
- }
-
- final int productId = usbDevice.getProductId();
- for (int supportedProductId : supportedProducts) {
- if (productId == supportedProductId) {
- return true;
- }
- }
- return false;
- }
-
}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/util/SerialInputOutputManager.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/util/SerialInputOutputManager.java
index d0be45e..d85a592 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/util/SerialInputOutputManager.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/util/SerialInputOutputManager.java
@@ -1,4 +1,5 @@
-/* Copyright 2011 Google Inc.
+/* Copyright 2011-2013 Google Inc.
+ * Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
- * Project home page: http://code.google.com/p/usb-serial-for-android/
+ * Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.util;
@@ -23,13 +24,13 @@ package com.hoho.android.usbserial.util;
import android.hardware.usb.UsbRequest;
import android.util.Log;
-import com.hoho.android.usbserial.driver.UsbSerialDriver;
+import com.hoho.android.usbserial.driver.UsbSerialPort;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
- * Utility class which services a {@link UsbSerialDriver} in its {@link #run()}
+ * Utility class which services a {@link UsbSerialPort} in its {@link #run()}
* method.
*
* @author mike wakerly (opensource@hoho.com)
@@ -42,7 +43,7 @@ public class SerialInputOutputManager implements Runnable {
private static final int READ_WAIT_MILLIS = 200;
private static final int BUFSIZ = 4096;
- private final UsbSerialDriver mDriver;
+ private final UsbSerialPort mDriver;
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
@@ -77,14 +78,14 @@ public class SerialInputOutputManager implements Runnable {
/**
* Creates a new instance with no listener.
*/
- public SerialInputOutputManager(UsbSerialDriver driver) {
+ public SerialInputOutputManager(UsbSerialPort driver) {
this(driver, null);
}
/**
* Creates a new instance with the provided listener.
*/
- public SerialInputOutputManager(UsbSerialDriver driver, Listener listener) {
+ public SerialInputOutputManager(UsbSerialPort driver, Listener listener) {
mDriver = driver;
mListener = listener;
}
From e62e95be2e3882c685e310f602e18cbae1f14178 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20H=C3=A4dicke?=
Date: Wed, 5 Jun 2013 23:37:55 +0200
Subject: [PATCH 02/12] Rename Cp2102SerialDriver to Cp21xxSerialDriver and add
Usb IDs for more Silabs devices
Conflicts:
UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
---
...ialDriver.java => Cp21xxSerialDriver.java} | 43 ++++++++++---------
.../hoho/android/usbserial/driver/UsbId.java | 7 ++-
.../usbserial/driver/UsbSerialProber.java | 2 +-
3 files changed, 29 insertions(+), 23 deletions(-)
rename UsbSerialLibrary/src/com/hoho/android/usbserial/driver/{Cp2102SerialDriver.java => Cp21xxSerialDriver.java} (91%)
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
similarity index 91%
rename from UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
rename to UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
index a427a18..7125104 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
@@ -34,16 +34,16 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-public class Cp2102SerialDriver implements UsbSerialDriver {
+public class Cp21xxSerialDriver implements UsbSerialDriver {
- private static final String TAG = Cp2102SerialDriver.class.getSimpleName();
+ private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
- public Cp2102SerialDriver(UsbDevice device) {
+ public Cp21xxSerialDriver(UsbDevice device) {
mDevice = device;
- mPort = new Cp2102SerialPort(mDevice);
+ mPort = new Cp21xxSerialPort(mDevice);
}
@Override
@@ -56,7 +56,7 @@ public class Cp2102SerialDriver implements UsbSerialDriver {
return Collections.singletonList(mPort);
}
- class Cp2102SerialPort extends CommonUsbSerialPort {
+ public class Cp21xxSerialPort extends CommonUsbSerialPort {
private static final int DEFAULT_BAUD_RATE = 9600;
@@ -104,13 +104,13 @@ public class Cp2102SerialDriver implements UsbSerialDriver {
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
- public Cp2102SerialPort(UsbDevice device) {
+ public Cp21xxSerialPort(UsbDevice device) {
super(device);
}
@Override
public UsbSerialDriver getDriver() {
- return Cp2102SerialDriver.this;
+ return Cp21xxSerialDriver.this;
}
private int setConfigSingle(int request, int value) {
@@ -330,27 +330,30 @@ public class Cp2102SerialDriver implements UsbSerialDriver {
public void setRTS(boolean value) throws IOException {
}
- @Override
- public boolean purgeHwBuffers(boolean purgeReadBuffers,
- boolean purgeWriteBuffers) throws IOException {
- int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
- | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
+ @Override
+ public boolean purgeHwBuffers(boolean purgeReadBuffers,
+ boolean purgeWriteBuffers) throws IOException {
+ int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
+ | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
- if (value != 0) {
- setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
- }
+ if (value != 0) {
+ setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
+ }
- return true;
- }
+ return true;
+ }
}
public static Map getSupportedDevices() {
final Map supportedDevices = new LinkedHashMap();
- supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILAB),
+ supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS),
new int[] {
- UsbId.SILAB_CP2102
- });
+ UsbId.SILABS_CP2102,
+ UsbId.SILABS_CP2105,
+ UsbId.SILABS_CP2108,
+ UsbId.SILABS_CP2110
+ });
return supportedDevices;
}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
index b837c8a..ae92a41 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
@@ -55,8 +55,11 @@ public final class UsbId {
public static final int VENDOR_LEAFLABS = 0x1eaf;
public static final int LEAFLABS_MAPLE = 0x0004;
- public static final int VENDOR_SILAB = 0x10c4;
- public static final int SILAB_CP2102 = 0xea60;
+ public static final int VENDOR_SILABS = 0x10c4;
+ public static final int SILABS_CP2102 = 0xea60;
+ public static final int SILABS_CP2105 = 0xea70;
+ public static final int SILABS_CP2108 = 0xea71;
+ public static final int SILABS_CP2110 = 0xea80;
public static final int VENDOR_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303;
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
index d00bf63..222ab60 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
@@ -44,7 +44,7 @@ public class UsbSerialProber {
public static UsbSerialProber getDefaultProber() {
final ProbeTable probeTable = new ProbeTable();
probeTable.addDriver(CdcAcmSerialDriver.class);
- probeTable.addDriver(Cp2102SerialDriver.class);
+ probeTable.addDriver(Cp21xxSerialDriver.class);
probeTable.addDriver(FtdiSerialDriver.class);
probeTable.addDriver(ProlificSerialDriver.class);
return new UsbSerialProber(probeTable);
From 8a152071b434d9ab53715dc8a77888b862171b83 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Mon, 28 Oct 2013 18:33:23 -0700
Subject: [PATCH 03/12] Update README.md
---
README.md | 81 ++++++++++++++++++++++++++----------
UsbSerialExamples/.classpath | 2 +-
UsbSerialLibrary/.classpath | 1 +
3 files changed, 62 insertions(+), 22 deletions(-)
diff --git a/README.md b/README.md
index db956d4..331b7f8 100644
--- a/README.md
+++ b/README.md
@@ -15,13 +15,11 @@ functions for use with your own protocols.
## Quick Start
-**1.** Download [usb-serial-for-android-v010.jar](https://github.com/mik3y/usb-serial-for-android/releases/download/v0.1.0/usb-serial-for-android-v010.jar)
+**1.** [Link your project](https://github.com/mik3y/usb-serial-for-android/wiki/Building-From-Source) to the library.
-**2.** Copy the jar to your Android project's `libs/` directory. (See [Android's FAQ](http://developer.android.com/guide/faq/commontasks.html#addexternallibrary) for help).
+**2.** Copy [device_filter.xml](http://usb-serial-for-android.googlecode.com/git/UsbSerialExamples/res/xml/device_filter.xml) to your project's `res/xml/` directory.
-**3.** Copy [device_filter.xml](http://usb-serial-for-android.googlecode.com/git/UsbSerialExamples/res/xml/device_filter.xml) to your project's `res/xml/` directory.
-
-**4.** 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).
+**3.** Configure your `AndroidManifest.xml` to notify your app when a device is attached (see [Android USB Host documentation](http://developer.android.com/guide/topics/connectivity/usb/host.html#discovering-d) for help).
```xml
availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
+if (availableDrivers.isEmpty()) {
+ return;
+}
-// Find the first available driver.
-UsbSerialDriver driver = UsbSerialProber.acquire(manager);
+// Open a connection to the first available driver.
+UsbSerialDriver driver = availableDrivers.get(0);
+UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
+if (connection == null) {
+ // You probably need to call UsbManager.requestPermission(driver.getDevice(), ..)
+ return;
+}
-if (driver != null) {
- driver.open();
- try {
- driver.setBaudRate(115200);
-
- byte buffer[] = new byte[16];
- int numBytesRead = driver.read(buffer, 1000);
- Log.d(TAG, "Read " + numBytesRead + " bytes.");
- } catch (IOException e) {
- // Deal with error.
- } finally {
- driver.close();
- }
+// Read some data! Most have just one port (port 0).
+UsbSerialPort port = driver.getPort(0);
+port.open(connection);
+try {
+ port.setBaudRate(115200);
+ byte buffer[] = new byte[16];
+ int numBytesRead = port.read(buffer, 1000);
+ Log.d(TAG, "Read " + numBytesRead + " bytes.");
+} catch (IOException e) {
+ // Deal with error.
+} finally {
+ port.close();
}
```
@@ -68,6 +74,39 @@ in git, which is a simple application for reading and showing serial data.
A [simple Arduino application](https://github.com/mik3y/usb-serial-for-android/blob/master/arduino)
is also available which can be used for testing.
+
+## Probing for Unrecognized Devices
+
+Sometimes you may need to do a little extra work to support devices which
+usb-serial-for-android doesn't [yet] know about -- but which you know to be
+compatible with one of the built-in drivers. This may be the case for a brand
+new device or for one using a custom VID/PID pair.
+
+UsbSerialProber is a class to help you find and instantiate compatible
+UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use
+the default prober returned by ``UsbSerialProber.getDefaultProber()``, which
+uses the built-in list of well-known VIDs and PIDs that are supported by our
+drivers.
+
+To use your own set of rules, create and use a custom prober:
+
+```java
+// Probe for our custom CDC devices, which use VID 0x1234
+// and PIDS 0x0001 and 0x0002.
+ProbeTable customTable = new ProbeTable();
+probeTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class);
+probeTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class);
+
+UsbSerialProber prober = new UsbSerialProber(customTable);
+List drivers = prober.findAllDrivers(usbManager);
+// ...
+```
+
+Of course, nothing requires you to use UsbSerialProber at all: you can
+instantiate driver classes directly if you know what you're doing; just supply
+a compatible UsbDevice.
+
+
## Compatible Devices
* *Serial chips:* FT232R, CDC/ACM (eg Arduino Uno) and possibly others.
diff --git a/UsbSerialExamples/.classpath b/UsbSerialExamples/.classpath
index 202cbff..a789bb7 100644
--- a/UsbSerialExamples/.classpath
+++ b/UsbSerialExamples/.classpath
@@ -4,7 +4,7 @@
-
+
diff --git a/UsbSerialLibrary/.classpath b/UsbSerialLibrary/.classpath
index 6aed2eb..7bc01d9 100644
--- a/UsbSerialLibrary/.classpath
+++ b/UsbSerialLibrary/.classpath
@@ -4,5 +4,6 @@
+
From e4b3ed610c65c768696067fd3385b561dff8375e Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Tue, 4 Feb 2014 14:22:14 -0800
Subject: [PATCH 04/12] UsbSerialPort: Add port number to interface.
---
.../usbserial/driver/CdcAcmSerialDriver.java | 8 ++++----
.../usbserial/driver/CommonUsbSerialPort.java | 16 +++++++++++++++-
.../usbserial/driver/Cp21xxSerialDriver.java | 6 +++---
.../usbserial/driver/FtdiSerialDriver.java | 6 +++---
.../usbserial/driver/ProlificSerialDriver.java | 6 +++---
.../android/usbserial/driver/UsbSerialPort.java | 5 +++++
6 files changed, 33 insertions(+), 14 deletions(-)
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
index 3e764ab..da014b7 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
@@ -51,7 +51,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
public CdcAcmSerialDriver(UsbDevice device) {
mDevice = device;
- mPort = new CdcAdcmSerialPort(device);
+ mPort = new CdcAcmSerialPort(device, 0);
}
@Override
@@ -64,7 +64,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
return Collections.singletonList(mPort);
}
- class CdcAdcmSerialPort extends CommonUsbSerialPort {
+ class CdcAcmSerialPort extends CommonUsbSerialPort {
private UsbInterface mControlInterface;
private UsbInterface mDataInterface;
@@ -84,8 +84,8 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
private static final int SET_CONTROL_LINE_STATE = 0x22;
private static final int SEND_BREAK = 0x23;
- public CdcAdcmSerialPort(UsbDevice device) {
- super(device);
+ public CdcAcmSerialPort(UsbDevice device, int portNumber) {
+ super(device, portNumber);
}
@Override
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java
index d8a9e1f..3a83913 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java
@@ -37,6 +37,7 @@ abstract class CommonUsbSerialPort implements UsbSerialPort {
public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
protected final UsbDevice mDevice;
+ protected final int mPortNumber;
// non-null when open()
protected UsbDeviceConnection mConnection = null;
@@ -50,12 +51,20 @@ abstract class CommonUsbSerialPort implements UsbSerialPort {
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected byte[] mWriteBuffer;
- public CommonUsbSerialPort(UsbDevice device) {
+ public CommonUsbSerialPort(UsbDevice device, int portNumber) {
mDevice = device;
+ mPortNumber = portNumber;
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
}
+
+ @Override
+ public String toString() {
+ return String.format("<%s device_name=%s device_id=%s port_number=%s>",
+ getClass().getSimpleName(), mDevice.getDeviceName(),
+ mDevice.getDeviceId(), mPortNumber);
+ }
/**
* Returns the currently-bound USB device.
@@ -66,6 +75,11 @@ abstract class CommonUsbSerialPort implements UsbSerialPort {
return mDevice;
}
+ @Override
+ public int getPortNumber() {
+ return mPortNumber;
+ }
+
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for read operations. Most users should not need to change this.
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
index 7125104..e9c812c 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
@@ -43,7 +43,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
public Cp21xxSerialDriver(UsbDevice device) {
mDevice = device;
- mPort = new Cp21xxSerialPort(mDevice);
+ mPort = new Cp21xxSerialPort(mDevice, 0);
}
@Override
@@ -104,8 +104,8 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
- public Cp21xxSerialPort(UsbDevice device) {
- super(device);
+ public Cp21xxSerialPort(UsbDevice device, int portNumber) {
+ super(device, portNumber);
}
@Override
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
index 7aad732..218c0f0 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
@@ -106,7 +106,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
public FtdiSerialDriver(UsbDevice device) {
mDevice = device;
- mPort = new FtdiSerialPort(mDevice);
+ mPort = new FtdiSerialPort(mDevice, 0);
}
@Override
public UsbDevice getDevice() {
@@ -192,8 +192,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
*/
private static final boolean ENABLE_ASYNC_READS = false;
- public FtdiSerialPort(UsbDevice device) {
- super(device);
+ public FtdiSerialPort(UsbDevice device, int portNumber) {
+ super(device, portNumber);
}
@Override
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
index 526f684..249cf4f 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
@@ -50,7 +50,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
public ProlificSerialDriver(UsbDevice device) {
mDevice = device;
- mPort = new ProlificSerialPort(mDevice);
+ mPort = new ProlificSerialPort(mDevice, 0);
}
@Override
@@ -124,8 +124,8 @@ public class ProlificSerialDriver implements UsbSerialDriver {
private IOException mReadStatusException = null;
- public ProlificSerialPort(UsbDevice device) {
- super(device);
+ public ProlificSerialPort(UsbDevice device, int portNumber) {
+ super(device, portNumber);
}
@Override
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java
index 3cd0080..d4fa4a0 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialPort.java
@@ -85,6 +85,11 @@ public interface UsbSerialPort {
public static final int STOPBITS_2 = 2;
public UsbSerialDriver getDriver();
+
+ /**
+ * Port number within driver.
+ */
+ public int getPortNumber();
/**
* Opens and initializes the port. Upon success, caller must ensure that
From a331afaa1af7069d07c3a5bcea227b74f66fc1e2 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Tue, 4 Feb 2014 14:22:35 -0800
Subject: [PATCH 05/12] UsbSerialProber: Expose getDefaultProbeTable().
---
.../com/hoho/android/usbserial/driver/UsbSerialProber.java | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
index 222ab60..538ec75 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
@@ -42,12 +42,16 @@ public class UsbSerialProber {
}
public static UsbSerialProber getDefaultProber() {
+ return new UsbSerialProber(getDefaultProbeTable());
+ }
+
+ public static ProbeTable getDefaultProbeTable() {
final ProbeTable probeTable = new ProbeTable();
probeTable.addDriver(CdcAcmSerialDriver.class);
probeTable.addDriver(Cp21xxSerialDriver.class);
probeTable.addDriver(FtdiSerialDriver.class);
probeTable.addDriver(ProlificSerialDriver.class);
- return new UsbSerialProber(probeTable);
+ return probeTable;
}
/**
From 61714523fc65c13994880bf56c4b8639ef520efe Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Wed, 19 Mar 2014 21:51:09 -0700
Subject: [PATCH 06/12] Fix open().
Issue #53.
---
.../com/hoho/android/usbserial/driver/FtdiSerialDriver.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
index 218c0f0..e3bd660 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
@@ -243,10 +243,11 @@ public class FtdiSerialDriver implements UsbSerialDriver {
if (mConnection != null) {
throw new IOException("Already open");
}
+
boolean opened = false;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
- if (mConnection.claimInterface(mDevice.getInterface(i), true)) {
+ if (connection.claimInterface(mDevice.getInterface(i), true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
throw new IOException("Error claiming interface " + i);
From 66eec6c8700453afd3aa35dc59cbe7833fd8e875 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Wed, 19 Mar 2014 21:59:13 -0700
Subject: [PATCH 07/12] open(): Set mConnection eagerly, and clear on failure.
Similar to CdcAcmSerialDriver. Issue #53.
---
.../com/hoho/android/usbserial/driver/FtdiSerialDriver.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
index e3bd660..3950ddd 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
@@ -243,6 +243,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
if (mConnection != null) {
throw new IOException("Already open");
}
+ mConnection = connection;
boolean opened = false;
try {
@@ -258,8 +259,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
} finally {
if (!opened) {
close();
- } else {
- mConnection = connection;
+ mConnection = null;
}
}
}
From 9c577949b0c56fd3cc14b6df5a457a8647ad91c4 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Mon, 31 Mar 2014 23:12:52 -0700
Subject: [PATCH 08/12] Add ProbeDevice.
---
.../usbserial/driver/UsbSerialProber.java | 59 ++++++++++++-------
1 file changed, 37 insertions(+), 22 deletions(-)
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
index 538ec75..5fa935c 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
@@ -67,32 +67,47 @@ public class UsbSerialProber {
final List result = new ArrayList();
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
- final int vendorId = usbDevice.getVendorId();
- final int productId = usbDevice.getProductId();
-
- final Class extends UsbSerialDriver> driverClass =
- mProbeTable.findDriver(vendorId, productId);
- if (driverClass != null) {
- final UsbSerialDriver driver;
- try {
- final Constructor extends UsbSerialDriver> ctor =
- driverClass.getConstructor(UsbDevice.class);
- driver = ctor.newInstance(usbDevice);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- } catch (IllegalArgumentException e) {
- throw new RuntimeException(e);
- } catch (InstantiationException e) {
- throw new RuntimeException(e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
- }
+ final UsbSerialDriver driver = probeDevice(usbDevice);
+ if (driver != null) {
result.add(driver);
}
}
return result;
}
+
+ /**
+ * Probes a single device for a compatible driver.
+ *
+ * @param usbDevice the usb device to probe
+ * @return a new {@link UsbSerialDriver} compatible with this device, or
+ * {@code null} if none available.
+ */
+ public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {
+ final int vendorId = usbDevice.getVendorId();
+ final int productId = usbDevice.getProductId();
+
+ final Class extends UsbSerialDriver> driverClass =
+ mProbeTable.findDriver(vendorId, productId);
+ if (driverClass != null) {
+ final UsbSerialDriver driver;
+ try {
+ final Constructor extends UsbSerialDriver> ctor =
+ driverClass.getConstructor(UsbDevice.class);
+ driver = ctor.newInstance(usbDevice);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ return driver;
+ }
+ return null;
+ }
}
From 95592f984a8f60558b7f33187e91b14003ca0e5a Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Mon, 31 Mar 2014 23:40:49 -0700
Subject: [PATCH 09/12] Convert to gradle.
---
.gitignore | 28 +-
.idea/.name | 1 +
.idea/compiler.xml | 23 ++
.idea/copyright/profiles_settings.xml | 3 +
.idea/encodings.xml | 5 +
.idea/gradle.xml | 19 +
.idea/misc.xml | 128 +++++++
.idea/modules.xml | 11 +
.idea/scopes/scope_settings.xml | 5 +
.idea/vcs.xml | 7 +
UsbSerialExamples/.classpath | 10 -
UsbSerialExamples/.project | 33 --
.../.settings/org.eclipse.jdt.core.prefs | 280 --------------
.../.settings/org.eclipse.jdt.ui.prefs | 7 -
UsbSerialExamples/proguard.cfg | 40 --
UsbSerialExamples/project.properties | 12 -
UsbSerialLibrary/.classpath | 9 -
UsbSerialLibrary/.project | 33 --
.../.settings/org.eclipse.jdt.core.prefs | 349 ------------------
.../.settings/org.eclipse.jdt.ui.prefs | 7 -
UsbSerialLibrary/proguard.cfg | 36 --
UsbSerialLibrary/project.properties | 12 -
build.gradle | 15 +
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes
gradle/wrapper/gradle-wrapper.properties | 6 +
gradlew | 164 ++++++++
gradlew.bat | 90 +++++
settings.gradle | 1 +
usbSerialExamples/build.gradle | 24 ++
.../src/main}/AndroidManifest.xml | 0
.../examples/DeviceListActivity.java | 0
.../examples/SerialConsoleActivity.java | 0
.../main}/res/drawable-hdpi/ic_launcher.png | Bin
.../main}/res/drawable-ldpi/ic_launcher.png | Bin
.../main}/res/drawable-mdpi/ic_launcher.png | Bin
.../src/main}/res/layout/main.xml | 0
.../src/main}/res/layout/serial_console.xml | 0
.../src/main}/res/values/strings.xml | 0
.../src/main}/res/xml/device_filter.xml | 0
usbSerialForAndroid/build.gradle | 18 +
.../src/main}/AndroidManifest.xml | 0
.../com/hoho/android/usbserial/BuildInfo.java | 0
.../usbserial/driver/CdcAcmSerialDriver.java | 0
.../usbserial/driver/CommonUsbSerialPort.java | 0
.../usbserial/driver/Cp21xxSerialDriver.java | 0
.../usbserial/driver/FtdiSerialDriver.java | 0
.../android/usbserial/driver/ProbeTable.java | 0
.../driver/ProlificSerialDriver.java | 0
.../hoho/android/usbserial/driver/UsbId.java | 0
.../usbserial/driver/UsbSerialDriver.java | 0
.../usbserial/driver/UsbSerialPort.java | 0
.../usbserial/driver/UsbSerialProber.java | 0
.../driver/UsbSerialRuntimeException.java | 0
.../hoho/android/usbserial/util/HexDump.java | 0
.../util/SerialInputOutputManager.java | 0
55 files changed, 540 insertions(+), 836 deletions(-)
create mode 100644 .idea/.name
create mode 100644 .idea/compiler.xml
create mode 100644 .idea/copyright/profiles_settings.xml
create mode 100644 .idea/encodings.xml
create mode 100644 .idea/gradle.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/scopes/scope_settings.xml
create mode 100644 .idea/vcs.xml
delete mode 100644 UsbSerialExamples/.classpath
delete mode 100644 UsbSerialExamples/.project
delete mode 100644 UsbSerialExamples/.settings/org.eclipse.jdt.core.prefs
delete mode 100644 UsbSerialExamples/.settings/org.eclipse.jdt.ui.prefs
delete mode 100644 UsbSerialExamples/proguard.cfg
delete mode 100644 UsbSerialExamples/project.properties
delete mode 100644 UsbSerialLibrary/.classpath
delete mode 100644 UsbSerialLibrary/.project
delete mode 100644 UsbSerialLibrary/.settings/org.eclipse.jdt.core.prefs
delete mode 100644 UsbSerialLibrary/.settings/org.eclipse.jdt.ui.prefs
delete mode 100644 UsbSerialLibrary/proguard.cfg
delete mode 100644 UsbSerialLibrary/project.properties
create mode 100644 build.gradle
create mode 100644 gradle/wrapper/gradle-wrapper.jar
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100755 gradlew
create mode 100644 gradlew.bat
create mode 100644 settings.gradle
create mode 100644 usbSerialExamples/build.gradle
rename {UsbSerialExamples => usbSerialExamples/src/main}/AndroidManifest.xml (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main/java}/src/com/hoho/android/usbserial/examples/DeviceListActivity.java (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main/java}/src/com/hoho/android/usbserial/examples/SerialConsoleActivity.java (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/drawable-hdpi/ic_launcher.png (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/drawable-ldpi/ic_launcher.png (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/drawable-mdpi/ic_launcher.png (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/layout/main.xml (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/layout/serial_console.xml (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/values/strings.xml (100%)
rename {UsbSerialExamples => usbSerialExamples/src/main}/res/xml/device_filter.xml (100%)
create mode 100644 usbSerialForAndroid/build.gradle
rename {UsbSerialLibrary => usbSerialForAndroid/src/main}/AndroidManifest.xml (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/BuildInfo.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/FtdiSerialDriver.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/ProbeTable.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/ProlificSerialDriver.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/UsbId.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/UsbSerialDriver.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/UsbSerialPort.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/UsbSerialProber.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/util/HexDump.java (100%)
rename {UsbSerialLibrary/src => usbSerialForAndroid/src/main/java}/com/hoho/android/usbserial/util/SerialInputOutputManager.java (100%)
diff --git a/.gitignore b/.gitignore
index 3ad687f..6e915e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,21 @@
-UsbSerialLibrary/bin
-UsbSerialLibrary/gen
+# Studio/Gradle
+*.iml
+.gradle/
+build/
+
+# Intellij IDEA (see https://intellij-support.jetbrains.com/entries/23393067)
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/datasources.xml
+.idea/dataSources.ids
+
+# generated files
+bin/
+gen/
+
+# Eclipse/Android/Misc
+.metadata/
+local.properties
+*.DS_Store
+proguard/
-UsbSerialExamples/bin
-UsbSerialExamples/gen
-UsbSerialLibrary/dictionary.txt
-UsbSerialLibrary/local.properties
-UsbSerialLibrary/proguard-project.txt
-UsbSerialLibrary/build.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..88cdcce
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+usb-serial-for-android
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..217af47
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..c464048
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..57ff5da
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ localhost
+ 5050
+
+
+
+
+
+
+ Android API 19 Platform
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..bdbfa79
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..def6a6a
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/UsbSerialExamples/.classpath b/UsbSerialExamples/.classpath
deleted file mode 100644
index a789bb7..0000000
--- a/UsbSerialExamples/.classpath
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/UsbSerialExamples/.project b/UsbSerialExamples/.project
deleted file mode 100644
index a74aedb..0000000
--- a/UsbSerialExamples/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- UsbSerialExamples
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/UsbSerialExamples/.settings/org.eclipse.jdt.core.prefs b/UsbSerialExamples/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index d811575..0000000
--- a/UsbSerialExamples/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,280 +0,0 @@
-#Thu Jun 02 12:32:09 PDT 2011
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.6
-org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
-org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
-org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_after_package=1
-org.eclipse.jdt.core.formatter.blank_lines_before_field=0
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=1
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
-org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=false
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=true
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
-org.eclipse.jdt.core.formatter.comment.line_length=80
-org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
-org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
-org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=2
-org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
-org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
-org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
-org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
-org.eclipse.jdt.core.formatter.indentation.size=4
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_lines_in_comments=true
-org.eclipse.jdt.core.formatter.join_wrapped_lines=false
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=100
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=4
-org.eclipse.jdt.core.formatter.use_on_off_tags=false
-org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
-org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/UsbSerialExamples/.settings/org.eclipse.jdt.ui.prefs b/UsbSerialExamples/.settings/org.eclipse.jdt.ui.prefs
deleted file mode 100644
index 74f510c..0000000
--- a/UsbSerialExamples/.settings/org.eclipse.jdt.ui.prefs
+++ /dev/null
@@ -1,7 +0,0 @@
-eclipse.preferences.version=1
-formatter_profile=_Android
-formatter_settings_version=11
-org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=android;com;dalvik;gov;junit;libcore;net;org;java;javax;
-org.eclipse.jdt.ui.ondemandthreshold=99
-org.eclipse.jdt.ui.staticondemandthreshold=99
diff --git a/UsbSerialExamples/proguard.cfg b/UsbSerialExamples/proguard.cfg
deleted file mode 100644
index b1cdf17..0000000
--- a/UsbSerialExamples/proguard.cfg
+++ /dev/null
@@ -1,40 +0,0 @@
--optimizationpasses 5
--dontusemixedcaseclassnames
--dontskipnonpubliclibraryclasses
--dontpreverify
--verbose
--optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-
--keep public class * extends android.app.Activity
--keep public class * extends android.app.Application
--keep public class * extends android.app.Service
--keep public class * extends android.content.BroadcastReceiver
--keep public class * extends android.content.ContentProvider
--keep public class * extends android.app.backup.BackupAgentHelper
--keep public class * extends android.preference.Preference
--keep public class com.android.vending.licensing.ILicensingService
-
--keepclasseswithmembernames class * {
- native ;
-}
-
--keepclasseswithmembers class * {
- public (android.content.Context, android.util.AttributeSet);
-}
-
--keepclasseswithmembers class * {
- public (android.content.Context, android.util.AttributeSet, int);
-}
-
--keepclassmembers class * extends android.app.Activity {
- public void *(android.view.View);
-}
-
--keepclassmembers enum * {
- public static **[] values();
- public static ** valueOf(java.lang.String);
-}
-
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
-}
diff --git a/UsbSerialExamples/project.properties b/UsbSerialExamples/project.properties
deleted file mode 100644
index 117494e..0000000
--- a/UsbSerialExamples/project.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-12
-android.library.reference.1=../UsbSerialLibrary
diff --git a/UsbSerialLibrary/.classpath b/UsbSerialLibrary/.classpath
deleted file mode 100644
index 7bc01d9..0000000
--- a/UsbSerialLibrary/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/UsbSerialLibrary/.project b/UsbSerialLibrary/.project
deleted file mode 100644
index b8b86d8..0000000
--- a/UsbSerialLibrary/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- UsbSerialLibrary
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/UsbSerialLibrary/.settings/org.eclipse.jdt.core.prefs b/UsbSerialLibrary/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 1ecab4a..0000000
--- a/UsbSerialLibrary/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,349 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=error
-org.eclipse.jdt.core.compiler.problem.deadCode=error
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=error
-org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=error
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=error
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=error
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nullReference=error
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=error
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=error
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=error
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedImport=error
-org.eclipse.jdt.core.compiler.problem.unusedLabel=error
-org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=error
-org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
-org.eclipse.jdt.core.compiler.source=1.6
-org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
-org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
-org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_after_package=1
-org.eclipse.jdt.core.formatter.blank_lines_before_field=0
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=1
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
-org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=false
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=true
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
-org.eclipse.jdt.core.formatter.comment.line_length=80
-org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
-org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
-org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=2
-org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
-org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
-org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
-org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
-org.eclipse.jdt.core.formatter.indentation.size=4
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_lines_in_comments=true
-org.eclipse.jdt.core.formatter.join_wrapped_lines=false
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=100
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=4
-org.eclipse.jdt.core.formatter.use_on_off_tags=false
-org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
-org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/UsbSerialLibrary/.settings/org.eclipse.jdt.ui.prefs b/UsbSerialLibrary/.settings/org.eclipse.jdt.ui.prefs
deleted file mode 100644
index 74f510c..0000000
--- a/UsbSerialLibrary/.settings/org.eclipse.jdt.ui.prefs
+++ /dev/null
@@ -1,7 +0,0 @@
-eclipse.preferences.version=1
-formatter_profile=_Android
-formatter_settings_version=11
-org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=android;com;dalvik;gov;junit;libcore;net;org;java;javax;
-org.eclipse.jdt.ui.ondemandthreshold=99
-org.eclipse.jdt.ui.staticondemandthreshold=99
diff --git a/UsbSerialLibrary/proguard.cfg b/UsbSerialLibrary/proguard.cfg
deleted file mode 100644
index 12dd039..0000000
--- a/UsbSerialLibrary/proguard.cfg
+++ /dev/null
@@ -1,36 +0,0 @@
--optimizationpasses 5
--dontusemixedcaseclassnames
--dontskipnonpubliclibraryclasses
--dontpreverify
--verbose
--optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-
--keep public class * extends android.app.Activity
--keep public class * extends android.app.Application
--keep public class * extends android.app.Service
--keep public class * extends android.content.BroadcastReceiver
--keep public class * extends android.content.ContentProvider
--keep public class * extends android.app.backup.BackupAgentHelper
--keep public class * extends android.preference.Preference
--keep public class com.android.vending.licensing.ILicensingService
-
--keepclasseswithmembernames class * {
- native ;
-}
-
--keepclasseswithmembernames class * {
- public (android.content.Context, android.util.AttributeSet);
-}
-
--keepclasseswithmembernames class * {
- public (android.content.Context, android.util.AttributeSet, int);
-}
-
--keepclassmembers enum * {
- public static **[] values();
- public static ** valueOf(java.lang.String);
-}
-
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
-}
diff --git a/UsbSerialLibrary/project.properties b/UsbSerialLibrary/project.properties
deleted file mode 100644
index 786389e..0000000
--- a/UsbSerialLibrary/project.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-12
-android.library=true
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..0ffc737
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,15 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.9.+'
+ }
+}
+
+allprojects {
+ repositories {
+ mavenCentral()
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..8c0fb64a8698b08ecc4158d828ca593c4928e9dd
GIT binary patch
literal 49896
zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~
zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR
z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN
z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+
z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl-
zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo
z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy
z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I
zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~
z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu
z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J
z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa
zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5
zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh
zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK
zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A
zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw
zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E%
zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1
zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S|
zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh**
z
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