Android: Update Serial Drivers

This commit is contained in:
Holden
2024-05-15 05:05:54 -04:00
committed by Holden
parent 92144e4be9
commit c970caa027
23 changed files with 1393 additions and 3168 deletions
+1
View File
@@ -74,6 +74,7 @@ ui_*
# android
android/local.properties
*.class
# doxygen
src/html/
+2
View File
@@ -52,6 +52,8 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+7 -1
View File
@@ -5,13 +5,14 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.2'
classpath 'com.android.tools.build:gradle:8.4.1'
}
}
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
apply plugin: 'com.android.application'
@@ -19,6 +20,7 @@ apply plugin: 'com.android.application'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation 'androidx.core:core:1.12.0'
implementation 'com.github.mik3y:usb-serial-for-android:3.7.3'
}
android {
@@ -59,6 +61,10 @@ android {
options.incremental = true
}
buildFeatures {
buildConfig = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
Binary file not shown.
+88
View File
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="baud_rate">
<item>300</item>
<item>600</item>
<item>1200</item>
<item>4800</item>
<item>9600</item>
<item>19200</item>
<item>38400</item>
<item>57600</item>
<item>115200</item>
<item>230400</item>
<item>460800</item>
<item>921600</item>
<item>1000000</item>
<item>1500000</item>
<item>2000000</item>
<item>3000000</item>
<item>4000000</item>
<item>5000000</item>
<item>6000000</item>
<item>7000000</item>
<item>8000000</item>
<item>9000000</item>
<item>10000000</item>
<item>11000000</item>
<item>12000000</item>
</string-array>
<string-array name="stop_bits">
<item>1</item>
<item>2</item>
</string-array>
<string-array name="data_bits">
<item>7</item>
<item>8</item>
</string-array>
<string-array name="parity">
<item>none</item>
<item>odd</item>
<item>even</item>
<item>mark</item>
<item>space</item>
</string-array>
<string-array name="flow_control">
<item>none</item>
<item>CTS/RTS</item>
<item>DTR/DSR</item>
<item>XOFF/XON</item>
</string-array>
<string-array name="buffer_size">
<item>32768</item>
<item>1M</item>
<item>2M</item>
<item>3M</item>
<item>4M</item>
<item>5M</item>
<item>6M</item>
<item>7M</item>
<item>8M</item>
<item>9M</item>
<item>10M</item>
</string-array>
<string-array name="max_transfer_size">
<item>32768</item>
<item>16384</item>
<item>8192</item>
<item>4096</item>
<item>2048</item>
<item>1024</item>
<item>512</item>
<item>256</item>
<item>128</item>
<item>64</item>
</string-array>
<string-array name="read_modes">
<item>event: SerialInputOutputManager.onNewData()</item>
<item>direct: UsbSerialPort.read()</item>
</string-array>
</resources>
+8 -80
View File
@@ -1,83 +1,11 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string-array name="baud_rate">
<item>300</item>
<item>600</item>
<item>1200</item>
<item>4800</item>
<item>9600</item>
<item>19200</item>
<item>38400</item>
<item>57600</item>
<item>115200</item>
<item>230400</item>
<item>460800</item>
<item>921600</item>
<item>1000000</item>
<item>1500000</item>
<item>2000000</item>
<item>3000000</item>
<item>4000000</item>
<item>5000000</item>
<item>6000000</item>
<item>7000000</item>
<item>8000000</item>
<item>9000000</item>
<item>10000000</item>
<item>11000000</item>
<item>12000000</item>
</string-array>
<string-array name="stop_bits">
<item>1</item>
<item>2</item>
</string-array>
<string-array name="data_bits">
<item>7</item>
<item>8</item>
</string-array>
<string-array name="parity">
<item>none</item>
<item>odd</item>
<item>even</item>
<item>mark</item>
<item>space</item>
</string-array>
<string-array name="flow_control">
<item>none</item>
<item>CTS/RTS</item>
<item>DTR/DSR</item>
<item>XOFF/XON</item>
</string-array>
<string-array name="buffer_size">
<item>32768</item>
<item>1M</item>
<item>2M</item>
<item>3M</item>
<item>4M</item>
<item>5M</item>
<item>6M</item>
<item>7M</item>
<item>8M</item>
<item>9M</item>
<item>10M</item>
</string-array>
<string-array name="max_transfer_size">
<item>32768</item>
<item>16384</item>
<item>8192</item>
<item>4096</item>
<item>2048</item>
<item>1024</item>
<item>512</item>
<item>256</item>
<item>128</item>
<item>64</item>
</string-array>
<string name="devices">USB Devices</string>
<string name="CdcAcm">CDC ACM USB Device</string>
<string name="ChromeCcd">Chrome CCD USB Device</string>
<string name="Cp21xx">CP21XX USB Device</string>
<string name="FTDI">FTDI USB Device</string>
<string name="GsmModem">GSM Modem USB Device</string>
<string name="Prolific">Prolific USB Device</string>
<string name="Unknown">Unknown USB Device</string>
</resources>
+36 -14
View File
@@ -2,18 +2,40 @@
<resources>
<!-- Allow anything connected -->
<usb-device />
<!-- <usb-device vendor-id="1118" product-id="688"></usb-device> -->
<!-- <usb-device vendor-id="1027" product-id="24577" /> --> <!-- FT232RL -->
<!-- <usb-device vendor-id="1027" product-id="24596" /> --> <!-- FT232H -->
<!-- <usb-device vendor-id="1027" product-id="24592" /> --> <!-- FT2232C/D/HL -->
<!-- <usb-device vendor-id="1027" product-id="24593" /> --> <!-- FT4232HL -->
<!-- <usb-device vendor-id="1027" product-id="24597" /> --> <!-- FT230X -->
<!-- <usb-device vendor-id="1027" product-id="24604" /> --> <!-- FT4222 -->
<!-- <usb-device vendor-id="1412" product-id="45088" /> --> <!-- REX-USB60F -->
<!-- <usb-device vendor-id="1027" product-id="24641" /> --> <!-- FT4233HPQ -->
<!-- <usb-device vendor-id="1027" product-id="24643" /> --> <!-- FT4232HPQ -->
<!-- <usb-device vendor-id="1027" product-id="24640" /> --> <!-- FT2233HPQ-->
<!-- <usb-device vendor-id="1027" product-id="24642" /> --> <!-- FT4232HPQ -->
<!-- <usb-device vendor-id="1027" product-id="24645" /> --> <!-- FT232HPQ -->
<!-- <usb-device vendor-id="1027" product-id="24644" /> --> <!-- FT233HPQ -->
<!-- 0x0403 / 0x60??: FTDI -->
<!-- <usb-device vendor-id="1027" product-id="24577" /> --> <!-- 0x6001: FT232R -->
<!-- <usb-device vendor-id="1027" product-id="24592" /> --> <!-- 0x6010: FT2232H -->
<!-- <usb-device vendor-id="1027" product-id="24593" /> --> <!-- 0x6011: FT4232H -->
<!-- <usb-device vendor-id="1027" product-id="24596" /> --> <!-- 0x6014: FT232H -->
<!-- <usb-device vendor-id="1027" product-id="24597" /> --> <!-- 0x6015: FT230X, FT231X, FT234XD -->
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
<!-- <usb-device vendor-id="4292" product-id="60000" /> --> <!-- 0xea60: CP2102 and other CP210x single port devices -->
<!-- <usb-device vendor-id="4292" product-id="60016" /> --> <!-- 0xea70: CP2105 -->
<!-- <usb-device vendor-id="4292" product-id="60017" /> --> <!-- 0xea71: CP2108 -->
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
<!-- <usb-device vendor-id="1659" product-id="8963" /> --> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
<!-- <usb-device vendor-id="1659" product-id="9123" /> --> <!-- 0x23a3: PL2303GC -->
<!-- <usb-device vendor-id="1659" product-id="9139" /> --> <!-- 0x23b3: PL2303GB -->
<!-- <usb-device vendor-id="1659" product-id="9155" /> --> <!-- 0x23c3: PL2303GT -->
<!-- <usb-device vendor-id="1659" product-id="9171" /> --> <!-- 0x23d3: PL2303GL -->
<!-- <usb-device vendor-id="1659" product-id="9187" /> --> <!-- 0x23e3: PL2303GE -->
<!-- <usb-device vendor-id="1659" product-id="9203" /> --> <!-- 0x23f3: PL2303GS -->
<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
<!-- <usb-device vendor-id="6790" product-id="21795" /> --> <!-- 0x5523: CH341A -->
<!-- <usb-device vendor-id="6790" product-id="29987" /> --> <!-- 0x7523: CH340 -->
<!-- CDC driver -->
<!-- <usb-device vendor-id="9025" /> --> <!-- 0x2341 / ......: Arduino -->
<!-- <usb-device vendor-id="5824" product-id="1155" /> --> <!-- 0x16C0 / 0x0483: Teensyduino -->
<!-- <usb-device vendor-id="1003" product-id="8260" /> --> <!-- 0x03EB / 0x2044: Atmel Lufa -->
<!-- <usb-device vendor-id="7855" product-id="4" /> --> <!-- 0x1eaf / 0x0004: Leaflabs Maple -->
<!-- <usb-device vendor-id="3368" product-id="516" /> --> <!-- 0x0d28 / 0x0204: ARM mbed -->
<!-- <usb-device vendor-id="1155" product-id="22336" /> --> <!-- 0x0483 / 0x5740: ST CDC -->
<!-- <usb-device vendor-id="11914" product-id="5" /> --> <!-- 0x2E8A / 0x0005: Raspberry Pi Pico Micropython -->
<!-- <usb-device vendor-id="11914" product-id="10" /> --> <!-- 0x2E8A / 0x000A: Raspberry Pi Pico SDK -->
<!-- <usb-device vendor-id="6790" product-id="21972" /> --> <!-- 0x1A86 / 0x55D4: Qinheng CH9102F -->
</resources>
@@ -1,322 +0,0 @@
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* USB CDC/ACM serial driver implementation.
*
* @author mike wakerly (opensource@hoho.com)
* @see <a
* href="http://www.usb.org/developers/devclass_docs/usbcdc11.pdf">Universal
* Serial Bus Class Definitions for Communication Devices, v1.1</a>
*/
public class CdcAcmSerialDriver extends CommonUsbSerialDriver {
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
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 CdcAcmSerialDriver(UsbDevice device) {
super(device);
}
@Override
public void open() throws IOException {
Log.d(TAG, "device " + mDevice);
mControlInterface = null;
mDataInterface = null;
mWriteEndpoint = null;
mReadEndpoint = null;
// locate all needed interfaces
for(int i = 0; i < mDevice.getInterfaceCount();i++){
UsbInterface iface = mDevice.getInterface(i);
switch(iface.getInterfaceClass()){
case UsbConstants.USB_CLASS_COMM:
mControlInterface = iface;
Log.d(TAG, "control iface=" + iface);
break;
case UsbConstants.USB_CLASS_CDC_DATA:
mDataInterface = iface;
Log.d(TAG, "data iface=" + iface);
break;
default:
Log.d(TAG, "skipping iface=" + iface);
break;
}
}
// failback to the old way
if(mControlInterface == null) {
mControlInterface = mDevice.getInterface(0);
Log.d(TAG, "Failback: Control iface=" + mControlInterface);
}
if (!mConnection.claimInterface(mControlInterface, true)) {
throw new IOException("Could not claim control interface.");
}
mControlEndpoint = mControlInterface.getEndpoint(0);
Log.d(TAG, "Control endpoint: " + mControlEndpoint);
if(mDataInterface == null) {
mDataInterface = mDevice.getInterface(1);
Log.d(TAG, "Failback: data iface=" + mDataInterface);
}
if (!mConnection.claimInterface(mDataInterface, true)) {
throw new IOException("Could not claim data interface.");
}
for(int i = 0; i < mDataInterface.getEndpointCount(); i++) {
UsbEndpoint endpoint = mDataInterface.getEndpoint(i);
switch (endpoint.getDirection()) {
case UsbConstants.USB_DIR_OUT:
mWriteEndpoint = endpoint;
Log.d(TAG, "Write endpoint: " + mWriteEndpoint);
break;
case UsbConstants.USB_DIR_IN:
mReadEndpoint = endpoint;
Log.d(TAG, "Read endpoint: " + mReadEndpoint);
break;
}
}
if(mReadEndpoint == null || mWriteEndpoint == null){
// failback to the old method
mReadEndpoint = mDataInterface.getEndpoint(0);
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
mWriteEndpoint = mDataInterface.getEndpoint(1);
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;
}
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;
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);
}
//Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
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);
}
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);
}
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 getCD() throws IOException {
return false; // TODO
}
@Override
public boolean getCTS() throws IOException {
return false; // TODO
}
@Override
public boolean getDSR() throws IOException {
return false; // TODO
}
@Override
public boolean getDTR() throws IOException {
return mDtr;
}
@Override
public void setDTR(boolean value) throws IOException {
mDtr = value;
setDtrRts();
}
@Override
public boolean getRI() throws IOException {
return false; // TODO
}
@Override
public boolean getRTS() throws IOException {
return mRts;
}
@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<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),
new int[] {
UsbId.ARDUINO_UNO,
UsbId.ARDUINO_UNO_R3,
UsbId.ARDUINO_MEGA_2560,
UsbId.ARDUINO_MEGA_2560_R3,
UsbId.ARDUINO_SERIAL_ADAPTER,
UsbId.ARDUINO_SERIAL_ADAPTER_R3,
UsbId.ARDUINO_MEGA_ADK,
UsbId.ARDUINO_MEGA_ADK_R3,
UsbId.ARDUINO_LEONARDO,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),
new int[] {
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL),
new int[] {
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS),
new int[] {
UsbId.LEAFLABS_MAPLE,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PX4),
new int[] {
UsbId.DEVICE_PX4FMU,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_UBLOX),
new int[] {
UsbId.DEVICE_UBLOX_5,
UsbId.DEVICE_UBLOX_6,
UsbId.DEVICE_UBLOX_7,
UsbId.DEVICE_UBLOX_8,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_OPENPILOT),
new int[] {
UsbId.DEVICE_CC3D,
UsbId.DEVICE_REVOLUTION,
UsbId.DEVICE_SPARKY2,
UsbId.DEVICE_OPLINK,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUPILOT_CHIBIOS1),
new int[] {
UsbId.DEVICE_ARDUPILOT_CHIBIOS,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUPILOT_CHIBIOS2),
new int[] {
UsbId.DEVICE_ARDUPILOT_CHIBIOS,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_DRAGONLINK),
new int[] {
UsbId.DEVICE_DRAGONLINK,
});
return supportedDevices;
}
}
@@ -1,172 +0,0 @@
/* Copyright 2013 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import java.io.IOException;
/**
* A base class shared by several driver implementations.
*
* @author mike wakerly (opensource@hoho.com)
*/
abstract class CommonUsbSerialDriver implements UsbSerialDriver {
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 Object mReadBufferLock = new Object();
protected final Object mWriteBufferLock = new Object();
protected UsbDeviceConnection mConnection = null;
private int _permissionStatus = permissionStatusRequestRequired;
/** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
protected byte[] mReadBuffer;
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected byte[] mWriteBuffer;
public CommonUsbSerialDriver(UsbDevice device) {
mDevice = device;
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
}
@Override
public void setConnection(UsbDeviceConnection connection) {
mConnection = connection;
}
@Override
public int permissionStatus() {
return _permissionStatus;
}
@Override
public void setPermissionStatus(int permissionStatus) {
_permissionStatus = permissionStatus;
}
/**
* Returns the currently-bound USB device.
*
* @return the device
*/
@Override
public final UsbDevice getDevice() {
return mDevice;
}
/**
* Returns the currently-bound USB device connection.
*
* @return the device connection
*/
@Override
public final UsbDeviceConnection getDeviceConnection() {
return mConnection;
}
/**
* 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.
*
* @param bufferSize the size in bytes
*/
public final void setReadBufferSize(int bufferSize) {
synchronized (mReadBufferLock) {
if (bufferSize == mReadBuffer.length) {
return;
}
mReadBuffer = new byte[bufferSize];
}
}
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for write operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setWriteBufferSize(int bufferSize) {
synchronized (mWriteBufferLock) {
if (bufferSize == mWriteBuffer.length) {
return;
}
mWriteBuffer = new byte[bufferSize];
}
}
@Override
public abstract void open() throws IOException;
@Override
public abstract void close() throws IOException;
@Override
public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException;
@Override
public abstract int write(final byte[] src, final int timeoutMillis) throws IOException;
@Override
public abstract void setParameters(
int baudRate, int dataBits, int stopBits, int parity) throws IOException;
@Override
public abstract boolean getCD() throws IOException;
@Override
public abstract boolean getCTS() throws IOException;
@Override
public abstract boolean getDSR() throws IOException;
@Override
public abstract boolean getDTR() throws IOException;
@Override
public abstract void setDTR(boolean value) throws IOException;
@Override
public abstract boolean getRI() throws IOException;
@Override
public abstract boolean getRTS() throws IOException;
@Override
public abstract void setRTS(boolean value) throws IOException;
@Override
public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException {
return !flushReadBuffers && !flushWriteBuffers;
}
}
@@ -1,292 +0,0 @@
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
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;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
public Cp2102SerialDriver(UsbDevice device) {
super(device);
}
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() 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;
} 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) {
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;
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);
}
//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 setRTS(boolean value) throws IOException {
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILAB),
new int[] {
UsbId.SILAB_CP2102
});
return supportedDevices;
}
}
@@ -1,445 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
// IMPORTANT NOTE:
// This code has been modified from the original source. It now uses the FTDI driver provided by
// ftdichip.com to communicate with an FTDI device. The previous code did not work with all FTDI
// devices.
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedHashMap;
import java.util.Map;
import org.mavlink.qgroundcontrol.QGCActivity;
/**
* A {@link CommonUsbSerialDriver} implementation for a variety of FTDI devices
* <p>
* This driver is based on
* <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>, and is
* copyright and subject to the following terms:
*
* <pre>
* Copyright (C) 2003 by Intra2net AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation;
*
* opensource@intra2net.com
* http://www.intra2net.com/en/developer/libftdi
* </pre>
*
* </p>
* <p>
* Some FTDI devices have not been tested; see later listing of supported and
* unsupported devices. Devices listed as "supported" support the following
* features:
* <ul>
* <li>Read and write of serial data (see {@link #read(byte[], int)} and
* {@link #write(byte[], int)}.
* <li>Setting baud rate (see {@link #setBaudRate(int)}).
* </ul>
* </p>
* <p>
* Supported and tested devices:
* <ul>
* <li>{@value DeviceType#TYPE_R}</li>
* </ul>
* </p>
* <p>
* Unsupported but possibly working devices (please contact the author with
* feedback or patches):
* <ul>
* <li>{@value DeviceType#TYPE_2232C}</li>
* <li>{@value DeviceType#TYPE_2232H}</li>
* <li>{@value DeviceType#TYPE_4232H}</li>
* <li>{@value DeviceType#TYPE_AM}</li>
* <li>{@value DeviceType#TYPE_BM}</li>
* </ul>
* </p>
*
* @author mike wakerly (opensource@hoho.com)
* @see <a href="http://code.google.com/p/usb-serial-for-android/">USB Serial
* for Android project page</a>
* @see <a href="http://www.ftdichip.com/">FTDI Homepage</a>
* @see <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>
*/
public class FtdiSerialDriver extends CommonUsbSerialDriver {
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;
/**
* FTDI chip types.
*/
private static enum DeviceType {
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;
FT_Device m_ftDev;
/**
* 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);
}
/**
* 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) {
super(usbDevice);
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 void open() throws IOException {
D2xxManager ftD2xx = null;
try {
ftD2xx = D2xxManager.getInstance(QGCActivity.m_context);
} catch (D2xxManager.D2xxException ex) {
QGCActivity.qgcLogDebug("D2xxManager.getInstance threw exception: " + ex.getMessage());
}
if (ftD2xx == null) {
String errMsg = "Unable to retrieve D2xxManager instance.";
QGCActivity.qgcLogWarning(errMsg);
throw new IOException(errMsg);
}
QGCActivity.qgcLogDebug("Opened D2xxManager");
int DevCount = ftD2xx.createDeviceInfoList(QGCActivity.m_context);
QGCActivity.qgcLogDebug("Found " + DevCount + " ftdi devices.");
if (DevCount < 1) {
throw new IOException("No FTDI Devices found");
}
m_ftDev = null;
try {
m_ftDev = ftD2xx.openByIndex(QGCActivity.m_context, 0);
} catch (NullPointerException e) {
QGCActivity.qgcLogDebug("ftD2xx.openByIndex exception: " + e.getMessage());
} finally {
if (m_ftDev == null) {
throw new IOException("No FTDI Devices found");
}
}
QGCActivity.qgcLogDebug("Opened FTDI device.");
}
@Override
public void close() {
if (m_ftDev != null) {
try {
m_ftDev.close();
} catch (Exception e) {
QGCActivity.qgcLogWarning("close exception: " + e.getMessage());
}
m_ftDev = null;
}
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
int totalBytesRead = 0;
int bytesAvailable = m_ftDev.getQueueStatus();
if (bytesAvailable > 0) {
bytesAvailable = Math.min(4096, bytesAvailable);
try {
totalBytesRead = m_ftDev.read(dest, bytesAvailable, timeoutMillis);
} catch (NullPointerException e) {
final String errorMsg = "Error reading: " + e.getMessage();
QGCActivity.qgcLogWarning(errorMsg);
throw new IOException(errorMsg, e);
}
}
return totalBytesRead;
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
try {
m_ftDev.write(src);
return src.length;
} catch (Exception e) {
QGCActivity.qgcLogWarning("Error writing: " + e.getMessage());
}
return 0;
}
private int setBaudRate(int baudRate) throws IOException {
try {
m_ftDev.setBaudRate(baudRate);
return baudRate;
} catch (Exception e) {
QGCActivity.qgcLogWarning("Error setting baud rate: " + e.getMessage());
}
return 0;
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
setBaudRate(baudRate);
switch (dataBits) {
case 7:
dataBits = D2xxManager.FT_DATA_BITS_7;
break;
case 8:
default:
dataBits = D2xxManager.FT_DATA_BITS_8;
break;
}
switch (stopBits) {
default:
case 0:
stopBits = D2xxManager.FT_STOP_BITS_1;
break;
case 1:
stopBits = D2xxManager.FT_STOP_BITS_2;
break;
}
switch (parity) {
default:
case 0:
parity = D2xxManager.FT_PARITY_NONE;
break;
case 1:
parity = D2xxManager.FT_PARITY_ODD;
break;
case 2:
parity = D2xxManager.FT_PARITY_EVEN;
break;
case 3:
parity = D2xxManager.FT_PARITY_MARK;
break;
case 4:
parity = D2xxManager.FT_PARITY_SPACE;
break;
}
try {
m_ftDev.setDataCharacteristics((byte)dataBits, (byte)stopBits, (byte)parity);
} catch (Exception e) {
QGCActivity.qgcLogWarning("Error setDataCharacteristics: " + e.getMessage());
}
}
@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) {
try {
m_ftDev.purge(D2xxManager.FT_PURGE_RX);
} catch (Exception e) {
String errMsg = "Error purgeHwBuffers(RX): "+ e.getMessage();
QGCActivity.qgcLogWarning(errMsg);
throw new IOException(errMsg);
}
}
if (purgeWriteBuffers) {
try {
m_ftDev.purge(D2xxManager.FT_PURGE_TX);
} catch (Exception e) {
String errMsg = "Error purgeHwBuffers(TX): " + e.getMessage();
QGCActivity.qgcLogWarning(errMsg);
throw new IOException(errMsg);
}
}
return true;
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
new int[] {
UsbId.FTDI_FT232R,
UsbId.FTDI_FT231X,
});
/*
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PX4),
new int[] {
UsbId.DEVICE_PX4FMU
});
*/
return supportedDevices;
}
}
@@ -1,523 +0,0 @@
/* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
/*
* Ported to usb-serial-for-android
* by Felix Hädicke <felixhaedicke@web.de>
*
* Based on the pyprolific driver written
* by Emmanuel Blot <emmanuel.blot@free.fr>
* See https://github.com/eblot/pyftdi
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
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;
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));
}
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));
}
}
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));
}
}
}
} catch (IOException e) {
mReadStatusException = 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();
}
}
}
/* throw and clear an exception which occurred 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) {
super(device);
}
@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 occurred 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
}
}
}
}
@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 occurred while waiting for status read thread", e);
}
}
}
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;
}
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;
}
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);
}
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);
}
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);
}
if (purgeWriteBuffers) {
vendorOut(FLUSH_TX_REQUEST, 0, null);
}
return true;
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC),
new int[] { UsbId.PROLIFIC_PL2303, });
return supportedDevices;
}
}
@@ -1,88 +0,0 @@
/* Copyright 2012 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
/**
* Registry of USB vendor/product ID constants.
*
* Culled from various sources; see
* <a href="http://www.linux-usb.org/usb.ids">usb.ids</a> for one listing.
*
* @author mike wakerly (opensource@hoho.com)
*/
public final class UsbId {
public static final int VENDOR_FTDI = 0x0403;
public static final int FTDI_FT232R = 0x6001;
public static final int FTDI_FT231X = 0x6015;
public static final int VENDOR_PX4 = 0x26AC;
public static final int DEVICE_PX4FMU = 0x11;
public static final int VENDOR_ATMEL = 0x03EB;
public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
public static final int VENDOR_ARDUINO = 0x2341;
public static final int ARDUINO_UNO = 0x0001;
public static final int ARDUINO_MEGA_2560 = 0x0010;
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
public static final int ARDUINO_MEGA_ADK = 0x003f;
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
public static final int ARDUINO_UNO_R3 = 0x0043;
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
public static final int ARDUINO_LEONARDO = 0x8036;
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
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_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303;
public static final int VENDOR_UBLOX = 0x1546;
public static final int DEVICE_UBLOX_5 = 0x01a5;
public static final int DEVICE_UBLOX_6 = 0x01a6;
public static final int DEVICE_UBLOX_7 = 0x01a7;
public static final int DEVICE_UBLOX_8 = 0x01a8;
public static final int VENDOR_OPENPILOT = 0x20A0;
public static final int DEVICE_REVOLUTION = 0x415E;
public static final int DEVICE_OPLINK = 0x415C;
public static final int DEVICE_SPARKY2 = 0x41D0;
public static final int DEVICE_CC3D = 0x415D;
public static final int VENDOR_ARDUPILOT_CHIBIOS1 = 0x0483;
public static final int VENDOR_ARDUPILOT_CHIBIOS2 = 0x1209;
public static final int DEVICE_ARDUPILOT_CHIBIOS = 0x5740;
public static final int VENDOR_DRAGONLINK = 0x1FC9;
public static final int DEVICE_DRAGONLINK = 0x0083;
private UsbId() {
throw new IllegalAccessError("Non-instantiable class.");
}
}
@@ -1,238 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
import java.io.IOException;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
/**
* 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;
public static final int permissionStatusSuccess = 0;
public static final int permissionStatusDenied = 1;
public static final int permissionStatusRequested = 2;
public static final int permissionStatusRequestRequired = 3;
public static final int permissionStatusOpen = 4;
public int permissionStatus();
public void setPermissionStatus(int permissionStatus);
public void setConnection(UsbDeviceConnection connection);
/**
* Returns the currently-bound USB device.
*
* @return the device
*/
public UsbDevice getDevice();
/**
* Returns the currently-bound USB device.
*
* @return the device
*/
public UsbDeviceConnection getDeviceConnection();
/**
* Opens and initializes the device as a USB serial device. Upon success,
* caller must ensure that {@link #close()} is eventually called.
*
* @throws IOException on error opening or initializing the device.
*/
public void open() throws IOException;
/**
* Closes the serial device.
*
* @throws IOException on error closing the device.
*/
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;
}
@@ -1,224 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
// IMPORTANT NOTE:
// This source has been modified from the original such that testIfSupported only tests for a vendor id
// match. If that matches it allows all product ids through. This provides for better match on unknown boards.
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.util.Log;
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.
*
* <p/>
* 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.
*
* <p/>
* 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 {
// TODO(mikey): Too much boilerplate.
/**
* Prober for {@link FtdiSerialDriver}.
*
* @see FtdiSerialDriver
*/
FTDI_SERIAL {
@Override
public List<UsbSerialDriver> probe(final UsbManager manager, final UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, FtdiSerialDriver.getSupportedDevices())) {
return Collections.emptyList();
}
final UsbSerialDriver driver = new FtdiSerialDriver(usbDevice);
return Collections.singletonList(driver);
}
},
CDC_ACM_SERIAL {
@Override
public List<UsbSerialDriver> probe(UsbManager manager, UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, CdcAcmSerialDriver.getSupportedDevices())) {
return Collections.emptyList();
}
final UsbSerialDriver driver = new CdcAcmSerialDriver(usbDevice);
return Collections.singletonList(driver);
}
},
SILAB_SERIAL {
@Override
public List<UsbSerialDriver> probe(final UsbManager manager, final UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, Cp2102SerialDriver.getSupportedDevices())) {
return Collections.emptyList();
}
final UsbSerialDriver driver = new Cp2102SerialDriver(usbDevice);
return Collections.singletonList(driver);
}
},
PROLIFIC_SERIAL {
@Override
public List<UsbSerialDriver> probe(final UsbManager manager, final UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, ProlificSerialDriver.getSupportedDevices())) {
return Collections.emptyList();
}
final UsbSerialDriver driver = new ProlificSerialDriver(usbDevice);
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<UsbSerialDriver> 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}.
*
* <p/>
* 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<UsbSerialDriver> probedDevices = prober.probe(usbManager, usbDevice);
if (!probedDevices.isEmpty()) {
return probedDevices.get(0);
}
}
}
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<UsbSerialDriver> findAllDevices(final UsbManager usbManager) {
final List<UsbSerialDriver> result = new ArrayList<UsbSerialDriver>();
//Log.i("QGC_UsbSerialProber", "Looking for USB devices");
// For each UsbDevice, call probe() for each prober.
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
//Log.i("QGC_UsbSerialProber", "Probing device: " + usbDevice.getDeviceName() + " mid: " + usbDevice.getVendorId() + " pid: " + usbDevice.getDeviceId());
result.addAll(probeSingleDevice(usbManager, usbDevice));
}
return result;
}
/**
* Special method for testing a specific device for driver support,
* returning any compatible driver(s).
*
* <p/>
* 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<UsbSerialDriver> probeSingleDevice(final UsbManager usbManager,
UsbDevice usbDevice)
{
final List<UsbSerialDriver> result = new ArrayList<UsbSerialDriver>();
for (final UsbSerialProber prober : values()) {
final List<UsbSerialDriver> 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<UsbSerialDriver> 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<Integer, int[]> supportedDevices) {
return supportedDevices.containsKey(usbDevice.getVendorId());
}
}
@@ -1,46 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package com.hoho.android.usbserial.driver;
/**
* Generic unchecked exception for the usbserial package.
*
* @author mike wakerly (opensource@hoho.com)
*/
@SuppressWarnings("serial")
public class UsbSerialRuntimeException extends RuntimeException {
public UsbSerialRuntimeException() {
super();
}
public UsbSerialRuntimeException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
public UsbSerialRuntimeException(String detailMessage) {
super(detailMessage);
}
public UsbSerialRuntimeException(Throwable throwable) {
super(throwable);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
package org.mavlink.qgroundcontrol;
import com.hoho.android.usbserial.driver.ProbeTable;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.driver.CdcAcmSerialDriver;
import org.mavlink.qgroundcontrol.QGCUsbId;
// implements UsbSerialProber?
class QGCProber
{
static UsbSerialProber getQGCProber()
{
final ProbeTable customTable = new ProbeTable();
return new UsbSerialProber(customTable);
}
}
@@ -0,0 +1,125 @@
package org.mavlink.qgroundcontrol;
public final class QGCUsbId {
public static final int VENDOR_FTDI = 0x0403;
public static final int FTDI_FT232R = 0x6001;
public static final int FTDI_FT2232H = 0x6010;
public static final int FTDI_FT4232H = 0x6011;
public static final int FTDI_FT232H = 0x6014;
public static final int FTDI_FT231X = 0x6015; // same ID for FT230X, FT231X, FT234XD
public static final int VENDOR_SILABS = 0x10c4;
public static final int SILABS_CP2102 = 0xea60; // same ID for CP2101, CP2103, CP2104, CP2109
public static final int SILABS_CP2105 = 0xea70;
public static final int SILABS_CP2108 = 0xea71;
public static final int VENDOR_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303; // device type 01, T, HX
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
public static final int PROLIFIC_PL2303GT = 0x23c3; // "
public static final int PROLIFIC_PL2303GL = 0x23d3; // "
public static final int PROLIFIC_PL2303GE = 0x23e3; // "
public static final int PROLIFIC_PL2303GS = 0x23f3; // "
public static final int VENDOR_GOOGLE = 0x18d1;
public static final int GOOGLE_CR50 = 0x5014;
public static final int VENDOR_QINHENG = 0x1a86;
public static final int QINHENG_CH340 = 0x7523;
public static final int QINHENG_CH341A = 0x5523;
public static final int VENDOR_UNISOC = 0x1782;
public static final int FIBOCOM_L610 = 0x4D10;
public static final int FIBOCOM_L612 = 0x4D12;
//////////////////////////////////////////////
public static final int VENDOR_PX4 = 0x26AC;
public static final int DEVICE_PX4FMU_V1 = 0x0010;
public static final int DEVICE_PX4FMU_V2 = 0x0011;
public static final int DEVICE_PX4FMU_V3 = 0x0011;
public static final int DEVICE_PX4FMU_V4 = 0x0012;
public static final int DEVICE_PX4FMU_V4PRO = 0x0013;
public static final int DEVICE_PX4FMU_V5 = 0x0032;
public static final int DEVICE_PX4FMU_V5X = 0x0033;
public static final int DEVICE_PX4FMU_V6C = 0x0038;
public static final int DEVICE_PX4FMU_V6U = 0x0036;
public static final int DEVICE_PX4FMU_V6X = 0x0035;
public static final int DEVICE_PX4FMU_V6XRT = 0x001D;
public static final int DEVICE_PX4MINDPX_V2 = 0x0030;
public static final int VENDOR_ATMEL = 0x03EB;
public static final int DEVICE_ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
public static final int VENDOR_ARDUINO = 0x2341;
public static final int DEVICE_ARDUINO_UNO = 0x0001;
public static final int DEVICE_ARDUINO_MEGA_2560 = 0x0010;
public static final int DEVICE_ARDUINO_SERIAL_ADAPTER = 0x003b;
public static final int DEVICE_ARDUINO_MEGA_ADK = 0x003f;
public static final int DEVICE_ARDUINO_MEGA_2560_R3 = 0x0042;
public static final int DEVICE_ARDUINO_UNO_R3 = 0x0043;
public static final int DEVICE_ARDUINO_MEGA_ADK_R3 = 0x0044;
public static final int DEVICE_ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
public static final int DEVICE_ARDUINO_LEONARDO = 0x8036;
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
public static final int DEVICE_VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
public static final int VENDOR_LEAFLABS = 0x1eaf;
public static final int DEVICE_LEAFLABS_MAPLE = 0x0004;
public static final int VENDOR_UBLOX = 0x1546;
public static final int DEVICE_UBLOX_5 = 0x01a5;
public static final int DEVICE_UBLOX_6 = 0x01a6;
public static final int DEVICE_UBLOX_7 = 0x01a7;
public static final int DEVICE_UBLOX_8 = 0x01a8;
public static final int VENDOR_OPENPILOT = 0x20A0;
public static final int DEVICE_REVOLUTION = 0x415E;
public static final int DEVICE_OPLINK = 0x415C;
public static final int DEVICE_SPARKY2 = 0x41D0;
public static final int DEVICE_CC3D = 0x415D;
public static final int VENDOR_STMICROELECTRONICS = 0x0483;
public static final int VENDOR_ARDUPILOT = 0x1209;
public static final int DEVICE_ARDUPILOT_CHIBIOS = 0x5740;
public static final int DEVICE_ARDUPILOT_CHIBIOS2 = 0x5741;
public static final int VENDOR_DRAGONLINK = 0x1FC9;
public static final int DEVICE_DRAGONLINK = 0x0083;
public static final int VENDOR_CUBEPILOT = 0x2DAE;
public static final int DEVICE_CUBE_BLACK = 0x1011;
public static final int DEVICE_CUBE_BLACK_BOOTLOADER = 0x1001;
public static final int DEVICE_CUBE_BLACK_PLUS = 0x1011;
public static final int DEVICE_CUBE_ORANGE = 0x1016;
public static final int DEVICE_CUBE_ORANGE2 = 0x1017;
public static final int DEVICE_CUBE_ORANGEPLUS = 0x1058;
public static final int DEVICE_CUBE_YELLOW_BOOTLOADER = 0x1002;
public static final int DEVICE_CUBE_YELLOW = 0x1012;
public static final int DEVICE_CUBE_PURPLE_BOOTLOADER = 0x1005;
public static final int DEVICE_CUBE_PURPLE = 0x1015;
public static final int VENDOR_CUAV = 0x3163;
public static final int DEVICE_CUAV_NORA = 0x004C;
public static final int DEVICE_CUAV_X7PRO = 0x004C;
public static final int VENDOR_HOLYBRO = 0x3162;
public static final int DEVICE_PIXHAWK4 = 0x0047;
public static final int DEVICE_PH4_MINI = 0x0049;
public static final int DEVICE_DURANDAL = 0x004B;
public static final int VENDOR_LASER_NAVIGATION = 0x27AC;
public static final int DEVICE_VRBRAIN_V51 = 0x1151;
public static final int DEVICE_VRBRAIN_V52 = 0x1152;
public static final int DEVICE_VRBRAIN_V54 = 0x1154;
public static final int DEVICE_VRCORE_V10 = 0x1910;
public static final int DEVICE_VRUBRAIN_V51 = 0x1351;
private QGCUsbId()
{
throw new IllegalAccessError("Non-instantiable class");
}
}
@@ -0,0 +1,265 @@
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly <opensource@hoho.com>
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package org.mavlink.qgroundcontrol;
import android.os.Process;
import android.util.Log;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Utility class which services a {@link UsbSerialPort} in its {@link #run()} method.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class SerialInputOutputManager implements Runnable {
public enum State {
STOPPED,
RUNNING,
STOPPING
}
public static boolean DEBUG = false;
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
private static final int BUFSIZ = 4096;
/**
* default read timeout is infinite, to avoid data loss with bulkTransfer API
*/
private int mReadTimeout = 0;
private int mWriteTimeout = 0;
private final Object mReadBufferLock = new Object();
private final Object mWriteBufferLock = new Object();
private ByteBuffer mReadBuffer; // default size = getReadEndpoint().getMaxPacketSize()
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
private State mState = State.STOPPED; // Synchronized by 'this'
private Listener mListener; // Synchronized by 'this'
private final UsbSerialPort mSerialPort;
private long mUserData;
public interface Listener {
/**
* Called when new incoming data is available.
*/
void onNewData(byte[] data, long userData);
/**
* Called when {@link SerialInputOutputManager#run()} aborts due to an error.
*/
void onRunError(Exception e, long userData);
}
public SerialInputOutputManager(UsbSerialPort serialPort) {
mSerialPort = serialPort;
mReadBuffer = ByteBuffer.allocate(serialPort.getReadEndpoint().getMaxPacketSize());
}
public SerialInputOutputManager(UsbSerialPort serialPort, Listener listener, long userData) {
mSerialPort = serialPort;
mListener = listener;
mUserData = userData;
mReadBuffer = ByteBuffer.allocate(serialPort.getReadEndpoint().getMaxPacketSize());
}
public synchronized void setListener(Listener listener) {
mListener = listener;
}
public synchronized Listener getListener() {
return mListener;
}
/**
* setThreadPriority. By default a higher priority than UI thread is used to prevent data loss
*
* @param threadPriority see {@link Process#setThreadPriority(int)}
* */
public void setThreadPriority(int threadPriority) {
if (mState != State.STOPPED)
throw new IllegalStateException("threadPriority only configurable before SerialInputOutputManager is started");
mThreadPriority = threadPriority;
}
/**
* read/write timeout
*/
public void setReadTimeout(int timeout) {
// when set if already running, read already blocks and the new value will not become effective now
if(mReadTimeout == 0 && timeout != 0 && mState != State.STOPPED)
throw new IllegalStateException("readTimeout only configurable before SerialInputOutputManager is started");
mReadTimeout = timeout;
}
public int getReadTimeout() {
return mReadTimeout;
}
public void setWriteTimeout(int timeout) {
mWriteTimeout = timeout;
}
public int getWriteTimeout() {
return mWriteTimeout;
}
/**
* read/write buffer size
*/
public void setReadBufferSize(int bufferSize) {
if (getReadBufferSize() == bufferSize)
return;
synchronized (mReadBufferLock) {
mReadBuffer = ByteBuffer.allocate(bufferSize);
}
}
public int getReadBufferSize() {
return mReadBuffer.capacity();
}
public void setWriteBufferSize(int bufferSize) {
if(getWriteBufferSize() == bufferSize)
return;
synchronized (mWriteBufferLock) {
ByteBuffer newWriteBuffer = ByteBuffer.allocate(bufferSize);
if(mWriteBuffer.position() > 0)
newWriteBuffer.put(mWriteBuffer.array(), 0, mWriteBuffer.position());
mWriteBuffer = newWriteBuffer;
}
}
public int getWriteBufferSize() {
return mWriteBuffer.capacity();
}
/**
* when using writeAsync, it is recommended to use readTimeout != 0,
* else the write will be delayed until read data is available
*/
public void writeAsync(byte[] data) {
synchronized (mWriteBufferLock) {
mWriteBuffer.put(data);
}
}
/**
* start SerialInputOutputManager in separate thread
*/
public void start() {
if(mState != State.STOPPED)
throw new IllegalStateException("already started");
new Thread(this, this.getClass().getSimpleName()).start();
}
/**
* stop SerialInputOutputManager thread
*
* when using readTimeout == 0 (default), additionally use usbSerialPort.close() to
* interrupt blocking read
*/
public synchronized void stop() {
if (getState() == State.RUNNING) {
Log.i(TAG, "Stop requested");
mState = State.STOPPING;
}
}
public synchronized State getState() {
return mState;
}
/**
* Continuously services the read and write buffers until {@link #stop()} is
* called, or until a driver exception is raised.
*/
@Override
public void run() {
synchronized (this) {
if (getState() != State.STOPPED) {
throw new IllegalStateException("Already running");
}
mState = State.RUNNING;
}
Log.i(TAG, "Running ...");
try {
if(mThreadPriority != Process.THREAD_PRIORITY_DEFAULT)
Process.setThreadPriority(mThreadPriority);
while (true) {
if (getState() != State.RUNNING) {
Log.i(TAG, "Stopping mState=" + getState());
break;
}
step();
}
} catch (Exception e) {
if(mSerialPort.isOpen()) {
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
} else {
Log.i(TAG, "Socket closed");
}
final Listener listener = getListener();
if (listener != null) {
listener.onRunError(e, mUserData);
}
} finally {
synchronized (this) {
mState = State.STOPPED;
Log.i(TAG, "Stopped");
}
}
}
private void step() throws IOException {
// Handle incoming data.
byte[] buffer;
synchronized (mReadBufferLock) {
buffer = mReadBuffer.array();
}
int len = mSerialPort.read(buffer, mReadTimeout);
if (len > 0) {
if (DEBUG) {
Log.d(TAG, "Read data len=" + len);
}
final Listener listener = getListener();
if (listener != null) {
final byte[] data = new byte[len];
System.arraycopy(buffer, 0, data, 0, len);
listener.onNewData(data, mUserData);
}
}
// Handle outgoing data.
buffer = null;
synchronized (mWriteBufferLock) {
len = mWriteBuffer.position();
if (len > 0) {
buffer = new byte[len];
mWriteBuffer.rewind();
mWriteBuffer.get(buffer, 0, len);
mWriteBuffer.clear();
}
}
if (buffer != null) {
if (DEBUG) {
Log.d(TAG, "Writing data len=" + len);
}
mSerialPort.write(buffer, mWriteTimeout);
}
}
}
@@ -1,218 +0,0 @@
package org.mavlink.qgroundcontrol;
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
import com.hoho.android.usbserial.driver.*;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.util.Log;
/**
* Utility class which services a {@link UsbSerialDriver} in its {@link #run()}
* method.
*
* Original author mike wakerly (opensource@hoho.com)
* Modified by Mike Goza
*/
public class UsbIoManager implements Runnable {
private static final int READ_WAIT_MILLIS = 100;
private static final int BUFSIZ = 4096;
private static final String TAG = "QGC_UsbIoManager";
private final UsbSerialDriver mDriver;
private long mUserData;
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private enum State
{
STOPPED,
RUNNING,
STOPPING
}
// Synchronized by 'this'
private State mState = State.STOPPED;
// Synchronized by 'this'
private Listener mListener;
public interface Listener
{
/**
* Called when new incoming data is available.
*/
public void onNewData(byte[] data, long userData);
/**
* Called when {@link SerialInputOutputManager#run()} aborts due to an
* error.
*/
public void onRunError(Exception e, long userData);
}
/**
* Creates a new instance with no listener.
*/
public UsbIoManager(UsbSerialDriver driver)
{
this(driver, null, 0);
Log.i(TAG, "Instance created");
}
/**
* Creates a new instance with the provided listener.
*/
public UsbIoManager(UsbSerialDriver driver, Listener listener, long userData)
{
mDriver = driver;
mListener = listener;
mUserData = userData;
}
public synchronized void setListener(Listener listener)
{
mListener = listener;
}
public synchronized Listener getListener()
{
return mListener;
}
public void writeAsync(byte[] data)
{
synchronized (mWriteBuffer)
{
mWriteBuffer.put(data);
}
}
public synchronized void stop()
{
if (getState() == State.RUNNING)
{
mState = State.STOPPING;
mUserData = 0;
}
}
private synchronized State getState()
{
return mState;
}
/**
* Continuously services the read and write buffers until {@link #stop()} is
* called, or until a driver exception is raised.
*/
@Override
public void run()
{
synchronized (this)
{
if (mState != State.STOPPED)
throw new IllegalStateException("Already running.");
mState = State.RUNNING;
}
try
{
while (true)
{
if (mState != State.RUNNING)
break;
step();
}
}
catch (Exception e)
{
final Listener listener = getListener();
if (listener != null)
listener.onRunError(e, mUserData);
}
finally
{
synchronized (this)
{
mState = State.STOPPED;
}
}
}
private void step() throws IOException
{
// Handle incoming data.
int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS);
if (len > 0)
{
final Listener listener = getListener();
if (listener != null)
{
final byte[] data = new byte[len];
mReadBuffer.get(data, 0, len);
listener.onNewData(data, mUserData);
}
mReadBuffer.clear();
}
/*
// Handle outgoing data.
byte[] outBuff = null;
synchronized (mWriteBuffer)
{
if (mWriteBuffer.position() > 0)
{
len = mWriteBuffer.position();
outBuff = new byte[len];
mWriteBuffer.rewind();
mWriteBuffer.get(outBuff, 0, len);
mWriteBuffer.clear();
}
}
if (outBuff != null)
mDriver.write(outBuff, READ_WAIT_MILLIS);
*/
}
}
@@ -51,7 +51,7 @@ QList<QSerialPortInfo> availablePortsByFiltersOfDevices(bool &ok)
const QJniObject result = QJniObject::callStaticObjectMethod(javaClass, methodId);
if (!result.isValid()) {
ok = false;
qCWarning(QSerialPortInfo_AndroidLog) << "Method Call Failed";
qCDebug(QSerialPortInfo_AndroidLog) << "Method Call Failed";
return QList<QSerialPortInfo>();
}
+13 -2
View File
@@ -121,11 +121,22 @@ if(ANDROID)
Qt6::CorePrivate
PUBLIC
Qt6::Core
Comms
Joystick
Comms
Joystick
)
target_include_directories(QGC PUBLIC ${CMAKE_SOURCE_DIR}/android/src)
if(!QGC_NO_SERIAL_LINK)
find_package(Qt6 REQUIRED COMPONENTS SerialPort)
target_link_libraries(QGC
PRIVATE
Qt6::SerialPortPrivate
PUBLIC
Qt6::SerialPort
)
endif()
else()
target_sources(QGC
PRIVATE