diff --git a/QGCApplication.pro b/QGCApplication.pro
index 6dbe2fa68bd555daae5366389ac9eaeca77fd9bc..9d57a82195229a0b60777f6ff0c1df1cfd8bd094 100644
--- a/QGCApplication.pro
+++ b/QGCApplication.pro
@@ -61,12 +61,15 @@ QT += network \
qml \
quick \
quickwidgets \
- serialport \
sql \
svg \
widgets \
xml \
+!AndroidBuild {
+ QT += serialport
+}
+
contains(DEFINES, QGC_NOTIFY_TUNES_ENABLED) {
QT += multimedia
}
@@ -78,6 +81,11 @@ QT += testlib
# OS Specific settings
#
+AndroidBuild {
+ DEFINES += __android__
+ DEFINES += __STDC_LIMIT_MACROS
+}
+
MacBuild {
QMAKE_INFO_PLIST = Custom-Info.plist
ICON = $$BASEDIR/resources/icons/macx.icns
@@ -173,9 +181,6 @@ FORMS += \
src/ui/designer/QGCToolWidgetComboBox.ui \
src/ui/designer/QGCXYPlot.ui \
src/ui/HDDisplay.ui \
- src/ui/JoystickAxis.ui \
- src/ui/JoystickButton.ui \
- src/ui/JoystickWidget.ui \
src/ui/Linechart.ui \
src/ui/MainWindow.ui \
src/ui/map/QGCMapTool.ui \
@@ -229,6 +234,13 @@ FORMS += \
src/ui/WaypointList.ui \
src/ui/WaypointViewOnlyView.ui \
+!AndroidBuild {
+FORMS += \
+ src/ui/JoystickButton.ui \
+ src/ui/JoystickAxis.ui \
+ src/ui/JoystickWidget.ui
+}
+
HEADERS += \
src/audio/QGCAudioWorker.h \
src/CmdLineOptParser.h \
@@ -250,7 +262,6 @@ HEADERS += \
src/comm/TCPLink.h \
src/comm/UDPLink.h \
src/GAudioOutput.h \
- src/input/JoystickInput.h \
src/LogCompressor.h \
src/MG.h \
src/QGC.h \
@@ -281,7 +292,6 @@ HEADERS += \
src/uas/UASParameterCommsMgr.h \
src/uas/UASParameterDataModel.h \
src/uas/UASWaypointManager.h \
- src/ui/CameraView.h \
src/ui/configuration/ApmHighlighter.h \
src/ui/configuration/console.h \
src/ui/configuration/SerialSettingsDialog.h \
@@ -300,9 +310,6 @@ HEADERS += \
src/ui/HDDisplay.h \
src/ui/HSIDisplay.h \
src/ui/HUD.h \
- src/ui/JoystickAxis.h \
- src/ui/JoystickButton.h \
- src/ui/JoystickWidget.h \
src/ui/linechart/ChartPlot.h \
src/ui/linechart/IncrementalPlot.h \
src/ui/linechart/LinechartPlot.h \
@@ -376,6 +383,15 @@ HEADERS += \
src/ViewWidgets/ViewWidgetController.h \
src/Waypoint.h \
+!AndroidBuild {
+HEADERS += \
+ src/input/JoystickInput.h \
+ src/ui/JoystickAxis.h \
+ src/ui/JoystickButton.h \
+ src/ui/JoystickWidget.h \
+ src/ui/CameraView.h \
+}
+
SOURCES += \
src/audio/QGCAudioWorker.cpp \
src/CmdLineOptParser.cc \
@@ -393,7 +409,6 @@ SOURCES += \
src/comm/TCPLink.cc \
src/comm/UDPLink.cc \
src/GAudioOutput.cc \
- src/input/JoystickInput.cc \
src/LogCompressor.cc \
src/main.cc \
src/QGC.cc \
@@ -418,7 +433,6 @@ SOURCES += \
src/uas/UASParameterCommsMgr.cc \
src/uas/UASParameterDataModel.cc \
src/uas/UASWaypointManager.cc \
- src/ui/CameraView.cc \
src/ui/configuration/ApmHighlighter.cc \
src/ui/configuration/console.cpp \
src/ui/configuration/SerialSettingsDialog.cc \
@@ -437,9 +451,6 @@ SOURCES += \
src/ui/HDDisplay.cc \
src/ui/HSIDisplay.cc \
src/ui/HUD.cc \
- src/ui/JoystickAxis.cc \
- src/ui/JoystickButton.cc \
- src/ui/JoystickWidget.cc \
src/ui/linechart/ChartPlot.cc \
src/ui/linechart/IncrementalPlot.cc \
src/ui/linechart/LinechartPlot.cc \
@@ -513,6 +524,15 @@ SOURCES += \
src/ViewWidgets/ViewWidgetController.cc \
src/Waypoint.cc \
+!AndroidBuild {
+SOURCES += \
+ src/input/JoystickInput.cc \
+ src/ui/JoystickAxis.cc \
+ src/ui/JoystickButton.cc \
+ src/ui/JoystickWidget.cc \
+ src/ui/CameraView.cc
+}
+
#
# Unit Test specific configuration goes here
#
@@ -524,6 +544,11 @@ SOURCES += \
DebugBuild|WindowsDebugAndRelease {
+HEADERS += src/QmlControls/QmlTestWidget.h
+SOURCES += src/QmlControls/QmlTestWidget.cc
+
+!AndroidBuild {
+
INCLUDEPATH += \
src/qgcunittest
@@ -550,7 +575,6 @@ HEADERS += \
src/qgcunittest/MockLinkMissionItemHandler.h \
src/qgcunittest/PX4RCCalibrationTest.h \
src/qgcunittest/UnitTest.h \
- src/QmlControls/QmlTestWidget.h \
src/VehicleSetup/SetupViewTest.h \
SOURCES += \
@@ -575,10 +599,10 @@ SOURCES += \
src/qgcunittest/MockLinkMissionItemHandler.cc \
src/qgcunittest/PX4RCCalibrationTest.cc \
src/qgcunittest/UnitTest.cc \
- src/QmlControls/QmlTestWidget.cc \
src/VehicleSetup/SetupViewTest.cc \
-}
+} # DebugBuild|WindowsDebugAndRelease
+} # AndroidBuild
#
# AutoPilot Plugin Support
@@ -658,3 +682,26 @@ SOURCES += \
src/FactSystem/FactSystem.cc \
src/FactSystem/FactValidator.cc \
src/FactSystem/ParameterLoader.cc \
+
+# Android
+
+AndroidBuild {
+ include($$PWD/libs/qtandroidserialport/src/qtandroidserialport.pri)
+ message("Adding Serial Java Classes")
+ QT += androidextras
+ ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
+ OTHER_FILES += \
+ $$PWD/android/AndroidManifest.xml \
+ $$PWD/android/res/xml/device_filter.xml \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/UsbId.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/UsbSerialProber.java \
+ $$PWD/android/src/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java \
+ $$PWD/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java \
+ $$PWD/android/src/org/qgroundcontrol/qgchelper/UsbIoManager.java
+}
diff --git a/QGCCommon.pri b/QGCCommon.pri
index b1e891af7e713c0f287330ba0aca4b336e66e202..ce362f1fa955fb65489669eef07637fc39a2d3e3 100644
--- a/QGCCommon.pri
+++ b/QGCCommon.pri
@@ -30,6 +30,10 @@ linux {
linux-g++ | linux-g++-64 {
message("Linux build")
CONFIG += LinuxBuild
+ } else : android-g++ {
+ message("Android build")
+ CONFIG += AndroidBuild
+ warning("Android build is experimental and not fully functional")
} else {
error("Unsuported Linux toolchain, only GCC 32- or 64-bit is supported")
}
diff --git a/QGCSetup.pri b/QGCSetup.pri
index ae7e716afcd1e3752c34779784f00ea0b911aad4..cce994557c81bf9a1832c27e47c7a425323283be 100644
--- a/QGCSetup.pri
+++ b/QGCSetup.pri
@@ -19,6 +19,10 @@
QMAKE_POST_LINK += echo "Copying files"
+AndroidBuild {
+ INSTALLS += $$DESTDIR
+}
+
#
# Copy the application resources to the associated place alongside the application
#
@@ -40,8 +44,10 @@ WindowsBuild {
BASEDIR_COPY_RESOURCE_LIST = $$replace(BASEDIR,"/","\\")
QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY_DIR \"$$BASEDIR_COPY_RESOURCE_LIST\\flightgear\" \"$$DESTDIR_COPY_RESOURCE_LIST\\flightgear\"
} else {
- # Make sure to keep both side of this if using the same set of directories
- QMAKE_POST_LINK += && $$QMAKE_COPY_DIR $$BASEDIR/flightgear $$DESTDIR_COPY_RESOURCE_LIST
+ !AndroidBuild {
+ # Make sure to keep both sides of this if using the same set of directories
+ QMAKE_POST_LINK += && $$QMAKE_COPY_DIR $$BASEDIR/flightgear $$DESTDIR_COPY_RESOURCE_LIST
+ }
}
#
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..21fcc18846fe7a5d125916d7b18a4e8044627469
--- /dev/null
+++ b/android/AndroidManifest.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..f487d95c0fb9f40af5ecd2d2feea9473bcd30a0a
Binary files /dev/null and b/android/res/drawable-ldpi/icon.png differ
diff --git a/android/res/xml/device_filter.xml b/android/res/xml/device_filter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a149a80b508d8f8978a9fdd66bfedd4b78ca4046
--- /dev/null
+++ b/android/res/xml/device_filter.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/android/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..3dec53a9a78daf83393b11a77147bcc3a21abe86
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
@@ -0,0 +1,252 @@
+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 Universal
+ * Serial Bus Class Definitions for Communication Devices, v1.1
+ */
+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, UsbDeviceConnection connection) {
+ super(device, connection);
+ }
+
+ @Override
+ public void open() throws IOException {
+ Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
+
+ Log.d(TAG, "Claiming control interface.");
+ 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());
+ }
+
+ 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 getSupportedDevices() {
+ final Map supportedDevices = new LinkedHashMap();
+ 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,
+ });
+ return supportedDevices;
+ }
+
+}
diff --git a/android/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java b/android/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..734933a22238264aa766ab39ec4365b3b4b0f50e
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java
@@ -0,0 +1,156 @@
+/* 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 UsbDeviceConnection mConnection;
+
+ protected final Object mReadBufferLock = new Object();
+ protected final Object mWriteBufferLock = new Object();
+
+ /** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
+ protected byte[] mReadBuffer;
+
+ /** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
+ protected byte[] mWriteBuffer;
+
+ public CommonUsbSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
+ mDevice = device;
+ mConnection = connection;
+
+ mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
+ mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
+ }
+
+ /**
+ * 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;
+ }
+
+}
+
diff --git a/android/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java b/android/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa151ba1a0e6887ea4b7985a43044dd4eb6fcbd2
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
@@ -0,0 +1,292 @@
+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, 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);
+ }
+
+ @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 getSupportedDevices() {
+ final Map supportedDevices = new LinkedHashMap();
+ supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILAB),
+ new int[] {
+ UsbId.SILAB_CP2102
+ });
+ return supportedDevices;
+ }
+
+
+}
diff --git a/android/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/android/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad3627ff38a75a50b71167ddf50f50b4ee5b1b51
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
@@ -0,0 +1,552 @@
+/* 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 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 java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A {@link CommonUsbSerialDriver} implementation for a variety of FTDI devices
+ *
+ * This driver is based on
+ * libftdi, and is
+ * copyright and subject to the following terms:
+ *
+ *
+ * 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
+ *
+ *
+ *
+ *
+ * Some FTDI devices have not been tested; see later listing of supported and
+ * 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)}).
+ *
+ *
+ *
+ * Supported and tested devices:
+ *
+ * - {@value DeviceType#TYPE_R}
+ *
+ *
+ *
+ * Unsupported but possibly working devices (please contact the author with
+ * feedback or patches):
+ *
+ * - {@value DeviceType#TYPE_2232C}
+ * - {@value DeviceType#TYPE_2232H}
+ * - {@value DeviceType#TYPE_4232H}
+ * - {@value DeviceType#TYPE_AM}
+ * - {@value DeviceType#TYPE_BM}
+ *
+ *
+ *
+ * @author mike wakerly (opensource@hoho.com)
+ * @see USB Serial
+ * for Android project page
+ * @see FTDI Homepage
+ * @see libftdi
+ */
+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;
+
+ /**
+ * 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, 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 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);
+ }
+ }
+ reset();
+ opened = true;
+ } finally {
+ if (!opened) {
+ close();
+ }
+ }
+ }
+
+ @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);
+ }
+
+ 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) {
+ return payloadBytesRead;
+ } else {
+ return 0;
+ }
+ } else {
+ final int totalBytesRead;
+
+ synchronized (mReadBufferLock) {
+ final int readAmt = Math.min(dest.length, mReadBuffer.length);
+ totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
+ readAmt, timeoutMillis);
+
+ if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
+ throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
+ }
+
+ return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());
+ }
+ }
+ }
+
+ @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;
+
+ 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(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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+ }
+
+ 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
+ } 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;
+ }
+ }
+ }
+
+ // 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;
+ }
+
+ public static Map getSupportedDevices() {
+ final Map supportedDevices = new LinkedHashMap();
+ 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;
+ }
+
+}
diff --git a/android/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/android/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6e2d1338d1a1f08051b5f13d2303a526c7a3639
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
@@ -0,0 +1,523 @@
+/* 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
+ *
+ * Based on the pyprolific driver written
+ * by Emmanuel Blot
+ * 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 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
+ }
+ }
+ }
+ }
+
+ @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);
+ }
+ }
+ }
+
+ 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 getSupportedDevices() {
+ final Map supportedDevices = new LinkedHashMap();
+ supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC),
+ new int[] { UsbId.PROLIFIC_PL2303, });
+ return supportedDevices;
+ }
+}
+
diff --git a/android/src/com/hoho/android/usbserial/driver/UsbId.java b/android/src/com/hoho/android/usbserial/driver/UsbId.java
new file mode 100644
index 0000000000000000000000000000000000000000..618fbc844b398d5179c566933761188a2553e810
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/UsbId.java
@@ -0,0 +1,69 @@
+/* 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
+ * usb.ids 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;
+
+ private UsbId() {
+ throw new IllegalAccessError("Non-instantiable class.");
+ }
+
+}
diff --git a/android/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java b/android/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed4426fc4d540238fc2cae9706adb41602a3a7a4
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
@@ -0,0 +1,228 @@
+/* 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;
+
+ /**
+ * 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;
+
+}
diff --git a/android/src/com/hoho/android/usbserial/driver/UsbSerialProber.java b/android/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cfb366e457f5957f84e42e48f7e10613f47cbb4
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
@@ -0,0 +1,250 @@
+/* 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 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.
+ *
+ *
+ * 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 {
+
+ // TODO(mikey): Too much boilerplate.
+
+ /**
+ * Prober for {@link FtdiSerialDriver}.
+ *
+ * @see FtdiSerialDriver
+ */
+ 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);
+ }
+ },
+
+ 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);
+ }
+ }
+ }
+ 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();
+ 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).
+ *
+ *
+ * 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/android/src/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java b/android/src/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..b48607c59da80c203031a252bcf1ee09d3a9b160
--- /dev/null
+++ b/android/src/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java
@@ -0,0 +1,46 @@
+/*
+ * 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);
+ }
+
+}
diff --git a/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java b/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java
new file mode 100644
index 0000000000000000000000000000000000000000..79d2597a116ef52b5539ebeb3cc223b43fe55f20
--- /dev/null
+++ b/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java
@@ -0,0 +1,637 @@
+package org.qgroundcontrol.qgchelper;
+
+/* 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/
+ */
+///////////////////////////////////////////////////////////////////////////////////////////
+// Written by: Mike Goza April 2014
+//
+// These routines interface with the Android USB Host devices for serial port communication.
+// The code uses the usb-serial-for-android software library. The UsbDeviceJNI class is the
+// interface to the C++ routines through jni calls. Do not change the functions without also
+// changing the corresponding calls in the C++ routines or you will break the interface.
+//
+////////////////////////////////////////////////////////////////////////////////////////////
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.io.IOException;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.*;
+import android.widget.Toast;
+import android.util.Log;
+
+import com.hoho.android.usbserial.driver.*;
+import org.qtproject.qt5.android.bindings.QtActivity;
+import org.qtproject.qt5.android.bindings.QtApplication;
+
+public class UsbDeviceJNI extends QtActivity
+{
+ public static int BAD_PORT = 0;
+ private static UsbDeviceJNI m_instance;
+ private static UsbManager m_manager; // ANDROID USB HOST CLASS
+ private static List m_devices; // LIST OF CURRENT DEVICES
+ private static HashMap m_openedDevices; // LIST OF OPENED DEVICES
+ private static HashMap m_ioManager; // THREADS FOR LISTENING FOR INCOMING DATA
+ private static HashMap m_userData; // CORRESPONDING USER DATA FOR OPENED DEVICES. USED IN DISCONNECT CALLBACK
+ // USED TO DETECT WHEN A DEVICE HAS BEEN UNPLUGGED
+ private BroadcastReceiver m_UsbReceiver = null;
+ private final static ExecutorService m_Executor = Executors.newSingleThreadExecutor();
+
+ private final static UsbIoManager.Listener m_Listener =
+ new UsbIoManager.Listener()
+ {
+ @Override
+ public void onRunError(Exception eA, int userDataA)
+ {
+ nativeDeviceException(userDataA, eA.getMessage());
+ }
+
+ @Override
+ public void onNewData(final byte[] dataA, int userDataA)
+ {
+ nativeDeviceNewData(userDataA, dataA);
+ }
+ };
+
+ private static final String TAG = "QGC_UsbDeviceJNI";
+
+ // NATIVE C++ FUNCTION THAT WILL BE CALLED IF THE DEVICE IS UNPLUGGED
+ private static native void nativeDeviceHasDisconnected(int userDataA);
+ private static native void nativeDeviceException(int userDataA, String messageA);
+ private static native void nativeDeviceNewData(int userDataA, byte[] dataA);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor. Only used once to create the initial instance for the static functions.
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ public UsbDeviceJNI()
+ {
+ m_instance = this;
+ m_openedDevices = new HashMap();
+ m_userData = new HashMap();
+ m_ioManager = new HashMap();
+ Log.i(TAG, "Instance created");
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Find all current devices that match the device filter described in the androidmanifest.xml and the
+ // device_filter.xml
+ //
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+ private static boolean getCurrentDevices()
+ {
+ if (m_instance == null)
+ return false;
+
+ if (m_manager == null)
+ m_manager = (UsbManager)m_instance.getSystemService(Context.USB_SERVICE);
+
+ if (m_devices != null)
+ m_devices.clear();
+
+ m_devices = UsbSerialProber.findAllDevices(m_manager);
+
+ return true;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // List all available devices that are not already open. It returns the serial port info
+ // in a : separated string array. Each string entry consists of the following:
+ //
+ // DeviceName:Company:ProductId:VendorId
+ //
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+ public static String[] availableDevicesInfo()
+ {
+ // GET THE LIST OF CURRENT DEVICES
+ if (!getCurrentDevices())
+ {
+ Log.e(TAG, "UsbDeviceJNI instance not present");
+ return null;
+ }
+
+ // MAKE SURE WE HAVE ENTRIES
+ if (m_devices.size() <= 0)
+ {
+ //Log.e(TAG, "No USB devices found");
+ return null;
+ }
+
+ if (m_openedDevices == null)
+ {
+ Log.e(TAG, "m_openedDevices is null");
+ return null;
+ }
+
+ int countL = 0;
+ int iL;
+
+ // CHECK FOR ALREADY OPENED DEVICES AND DON"T INCLUDE THEM IN THE COUNT
+ for (iL=0; iL 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);
+*/
+ }
+}
+
diff --git a/libs/qextserialport/src/qextserialport_unix.cpp b/libs/qextserialport/src/qextserialport_unix.cpp
index 97d7ac1a3416edba120f09479e8126fc94a983fd..78c486568147216a35916a2fbe1c49cb0eb7b444 100755
--- a/libs/qextserialport/src/qextserialport_unix.cpp
+++ b/libs/qextserialport/src/qextserialport_unix.cpp
@@ -120,7 +120,11 @@ bool QextSerialPortPrivate::close_sys()
bool QextSerialPortPrivate::flush_sys()
{
+#ifdef __android__
+ ::ioctl(fd, TCSADRAIN, ¤tTermios);
+#else
::tcdrain(fd);
+#endif
return true;
}
diff --git a/libs/qtandroidserialport/src/qserialport.cpp b/libs/qtandroidserialport/src/qserialport.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..992f06bfcfb79ae69efa7315cc198e300553e5f5
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialport.cpp
@@ -0,0 +1,1375 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov
+** Copyright (C) 2011 Sergey Belyashov
+** Copyright (C) 2012 Laszlo Papp
+** Copyright (C) 2012 Andre Hartmann
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qserialport.h"
+#include "qserialportinfo.h"
+#include "qserialportinfo_p.h"
+
+#ifdef Q_OS_WINCE
+#include "qserialport_wince_p.h"
+#elif defined (Q_OS_WIN)
+#include "qserialport_win_p.h"
+#elif defined (Q_OS_SYMBIAN)
+#include "qserialport_symbian_p.h"
+#elif defined (Q_OS_ANDROID)
+#include "qserialport_android_p.h"
+#elif defined (Q_OS_UNIX)
+#include "qserialport_unix_p.h"
+#else
+#error Unsupported OS
+#endif
+
+#ifndef SERIALPORT_BUFFERSIZE
+# define SERIALPORT_BUFFERSIZE 16384
+#endif
+
+#include
+
+QT_BEGIN_NAMESPACE
+
+QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q)
+ : readBufferMaxSize(0)
+ , readBuffer(SERIALPORT_BUFFERSIZE)
+ , writeBuffer(SERIALPORT_BUFFERSIZE)
+ , error(QSerialPort::NoError)
+ , inputBaudRate(9600)
+ , outputBaudRate(9600)
+ , dataBits(QSerialPort::Data8)
+ , parity(QSerialPort::NoParity)
+ , stopBits(QSerialPort::OneStop)
+ , flowControl(QSerialPort::NoFlowControl)
+ , policy(QSerialPort::IgnorePolicy)
+#if QT_DEPRECATED_SINCE(5,3)
+ , settingsRestoredOnClose(true)
+#endif
+ , q_ptr(q)
+{
+}
+
+int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return msecs;
+ msecs -= elapsed;
+ return qMax(msecs, 0);
+}
+
+/*!
+ \class QSerialPort
+
+ \brief Provides functions to access serial ports.
+
+ \reentrant
+ \ingroup serialport-main
+ \inmodule QtSerialPort
+ \since 5.1
+
+ You can get information about the available serial ports using the
+ QSerialPortInfo helper class, which allows an enumeration of all the serial
+ ports in the system. This is useful to obtain the correct name of the
+ serial port you want to use. You can pass an object
+ of the helper class as an argument to the setPort() or setPortName()
+ methods to assign the desired serial device.
+
+ After setting the port, you can open it in read-only (r/o), write-only
+ (w/o), or read-write (r/w) mode using the open() method.
+
+ \note The serial port is always opened with exclusive access
+ (that is, no other process or thread can access an already opened serial port).
+
+ Having successfully opened, QSerialPort tries to determine the current
+ configuration of the port and initializes itself. You can reconfigure the
+ port to the desired setting using the setBaudRate(), setDataBits(),
+ setParity(), setStopBits(), and setFlowControl() methods.
+
+ There are a couple of properties to work with the pinout signals namely:
+ QSerialPort::dataTerminalReady, QSerialPort::requestToSend. It is also
+ possible to use the pinoutSignals() method to query the current pinout
+ signals set.
+
+ Once you know that the ports are ready to read or write, you can
+ use the read() or write() methods. Alternatively the
+ readLine() and readAll() convenience methods can also be invoked.
+ If not all the data is read at once, the remaining data will
+ be available for later as new incoming data is appended to the
+ QSerialPort's internal read buffer. You can limit the size of the read
+ buffer using setReadBufferSize().
+
+ Use the close() method to close the port and cancel the I/O operations.
+
+ See the following example:
+
+ \code
+ int numRead = 0, numReadTotal = 0;
+ char buffer[50];
+
+ forever {
+ numRead = serial.read(buffer, 50);
+
+ // Do whatever with the array
+
+ numReadTotal += numRead;
+ if (numRead == 0 && !serial.waitForReadyRead())
+ break;
+ }
+ \endcode
+
+ If \l{QIODevice::}{waitForReadyRead()} returns false, the
+ connection has been closed or an error has occurred.
+
+ Programming with a blocking serial port is radically different from
+ programming with a non-blocking serial port. A blocking serial port
+ does not require an event loop and typically leads to simpler code.
+ However, in a GUI application, blocking serial port should only be
+ used in non-GUI threads, to avoid freezing the user interface.
+
+ For more details about these approaches, refer to the
+ \l {Examples}{example} applications.
+
+ The QSerialPort class can also be used with QTextStream and QDataStream's
+ stream operators (operator<<() and operator>>()). There is one issue to be
+ aware of, though: make sure that enough data is available before attempting
+ to read by using the operator>>() overloaded operator.
+
+ \sa QSerialPortInfo
+*/
+
+/*!
+ \enum QSerialPort::Direction
+
+ This enum describes the possible directions of the data transmission.
+
+ \note This enumeration is used for setting the baud rate of the device
+ separately for each direction on some operating systems (for example,
+ POSIX-like).
+
+ \value Input Input direction.
+ \value Output Output direction.
+ \value AllDirections Simultaneously in two directions.
+*/
+
+/*!
+ \enum QSerialPort::BaudRate
+
+ This enum describes the baud rate which the communication device operates
+ with.
+
+ \note Only the most common standard baud rates are listed in this enum.
+
+ \value Baud1200 1200 baud.
+ \value Baud2400 2400 baud.
+ \value Baud4800 4800 baud.
+ \value Baud9600 9600 baud.
+ \value Baud19200 19200 baud.
+ \value Baud38400 38400 baud.
+ \value Baud57600 57600 baud.
+ \value Baud115200 115200 baud.
+ \value UnknownBaud Unknown baud. This value is obsolete. It is provided to
+ keep old source code working. We strongly advise against
+ using it in new code.
+
+ \sa QSerialPort::baudRate
+*/
+
+/*!
+ \enum QSerialPort::DataBits
+
+ This enum describes the number of data bits used.
+
+ \value Data5 The number of data bits in each character is 5. It
+ is used for Baudot code. It generally only makes
+ sense with older equipment such as teleprinters.
+ \value Data6 The number of data bits in each character is 6. It
+ is rarely used.
+ \value Data7 The number of data bits in each character is 7. It
+ is used for true ASCII. It generally only makes
+ sense with older equipment such as teleprinters.
+ \value Data8 The number of data bits in each character is 8. It
+ is used for most kinds of data, as this size matches
+ the size of a byte. It is almost universally used in
+ newer applications.
+ \value UnknownDataBits Unknown number of bits. This value is obsolete. It
+ is provided to keep old source code working. We
+ strongly advise against using it in new code.
+
+ \sa QSerialPort::dataBits
+*/
+
+/*!
+ \enum QSerialPort::Parity
+
+ This enum describes the parity scheme used.
+
+ \value NoParity No parity bit it sent. This is the most common
+ parity setting. Error detection is handled by the
+ communication protocol.
+ \value EvenParity The number of 1 bits in each character, including
+ the parity bit, is always even.
+ \value OddParity The number of 1 bits in each character, including
+ the parity bit, is always odd. It ensures that at
+ least one state transition occurs in each character.
+ \value SpaceParity Space parity. The parity bit is sent in the space
+ signal condition. It does not provide error
+ detection information.
+ \value MarkParity Mark parity. The parity bit is always set to the
+ mark signal condition (logical 1). It does not
+ provide error detection information.
+ \value UnknownParity Unknown parity. This value is obsolete. It is
+ provided to keep old source code working. We
+ strongly advise against using it in new code.
+
+ \sa QSerialPort::parity
+*/
+
+/*!
+ \enum QSerialPort::StopBits
+
+ This enum describes the number of stop bits used.
+
+ \value OneStop 1 stop bit.
+ \value OneAndHalfStop 1.5 stop bits. This is only for the Windows platform.
+ \value TwoStop 2 stop bits.
+ \value UnknownStopBits Unknown number of stop bits. This value is obsolete.
+ It is provided to keep old source code working. We
+ strongly advise against using it in new code.
+
+ \sa QSerialPort::stopBits
+*/
+
+/*!
+ \enum QSerialPort::FlowControl
+
+ This enum describes the flow control used.
+
+ \value NoFlowControl No flow control.
+ \value HardwareControl Hardware flow control (RTS/CTS).
+ \value SoftwareControl Software flow control (XON/XOFF).
+ \value UnknownFlowControl Unknown flow control. This value is obsolete. It
+ is provided to keep old source code working. We
+ strongly advise against using it in new code.
+
+ \sa QSerialPort::flowControl
+*/
+
+/*!
+ \enum QSerialPort::PinoutSignal
+
+ This enum describes the possible RS-232 pinout signals.
+
+ \value NoSignal No line active
+ \value TransmittedDataSignal TxD (Transmitted Data). This value is
+ obsolete. It is provided to keep old
+ source code working. We strongly
+ advise against using it in new code.
+ \value ReceivedDataSignal RxD (Received Data). This value is
+ obsolete. It is provided to keep old
+ source code working. We strongly
+ advise against using it in new code.
+ \value DataTerminalReadySignal DTR (Data Terminal Ready).
+ \value DataCarrierDetectSignal DCD (Data Carrier Detect).
+ \value DataSetReadySignal DSR (Data Set Ready).
+ \value RingIndicatorSignal RNG (Ring Indicator).
+ \value RequestToSendSignal RTS (Request To Send).
+ \value ClearToSendSignal CTS (Clear To Send).
+ \value SecondaryTransmittedDataSignal STD (Secondary Transmitted Data).
+ \value SecondaryReceivedDataSignal SRD (Secondary Received Data).
+
+ \sa pinoutSignals(), QSerialPort::dataTerminalReady,
+ QSerialPort::requestToSend
+*/
+
+/*!
+ \enum QSerialPort::DataErrorPolicy
+ \obsolete
+
+ This enum describes the policies for the received symbols
+ while parity errors were detected.
+
+ \value SkipPolicy Skips the bad character.
+ \value PassZeroPolicy Replaces bad character with zero.
+ \value IgnorePolicy Ignores the error for a bad character.
+ \value StopReceivingPolicy Stops data reception on error.
+ \value UnknownPolicy Unknown policy.
+
+ \sa QSerialPort::dataErrorPolicy
+*/
+
+/*!
+ \enum QSerialPort::SerialPortError
+
+ This enum describes the errors that may be contained by the
+ QSerialPort::error property.
+
+ \value NoError No error occurred.
+
+ \value DeviceNotFoundError An error occurred while attempting to
+ open an non-existing device.
+
+ \value PermissionError An error occurred while attempting to
+ open an already opened device by another
+ process or a user not having enough permission
+ and credentials to open.
+
+ \value OpenError An error occurred while attempting to open an
+ already opened device in this object.
+
+ \value NotOpenError This error occurs when an operation is executed
+ that can only be successfully performed if the
+ device is open. This value was introduced in
+ QtSerialPort 5.2.
+
+ \value ParityError Parity error detected by the hardware while
+ reading data.
+
+ \value FramingError Framing error detected by the hardware while
+ reading data.
+
+ \value BreakConditionError Break condition detected by the hardware on
+ the input line.
+
+ \value WriteError An I/O error occurred while writing the data.
+
+ \value ReadError An I/O error occurred while reading the data.
+
+ \value ResourceError An I/O error occurred when a resource becomes
+ unavailable, e.g. when the device is
+ unexpectedly removed from the system.
+
+ \value UnsupportedOperationError The requested device operation is not
+ supported or prohibited by the running operating
+ system.
+
+ \value TimeoutError A timeout error occurred. This value was
+ introduced in QtSerialPort 5.2.
+
+ \value UnknownError An unidentified error occurred.
+ \sa QSerialPort::error
+*/
+
+
+
+/*!
+ Constructs a new serial port object with the given \a parent.
+*/
+QSerialPort::QSerialPort(QObject *parent)
+ : QIODevice(parent)
+ , d_ptr(new QSerialPortPrivate(this))
+{}
+
+/*!
+ Constructs a new serial port object with the given \a parent
+ to represent the serial port with the specified \a name.
+
+ The name should have a specific format; see the setPort() method.
+*/
+QSerialPort::QSerialPort(const QString &name, QObject *parent)
+ : QIODevice(parent)
+ , d_ptr(new QSerialPortPrivate(this))
+{
+ setPortName(name);
+}
+
+/*!
+ Constructs a new serial port object with the given \a parent
+ to represent the serial port with the specified helper class
+ \a serialPortInfo.
+*/
+QSerialPort::QSerialPort(const QSerialPortInfo &serialPortInfo, QObject *parent)
+ : QIODevice(parent)
+ , d_ptr(new QSerialPortPrivate(this))
+{
+ setPort(serialPortInfo);
+}
+
+/*!
+ Closes the serial port, if necessary, and then destroys object.
+*/
+QSerialPort::~QSerialPort()
+{
+ /**/
+ if (isOpen())
+ close();
+ delete d_ptr;
+}
+
+/*!
+ Sets the \a name of the serial port.
+
+ The name of the serial port can be passed as either a short name or
+ the long system location if necessary.
+
+ \sa portName(), QSerialPortInfo
+*/
+void QSerialPort::setPortName(const QString &name)
+{
+ Q_D(QSerialPort);
+ d->systemLocation = QSerialPortInfoPrivate::portNameToSystemLocation(name);
+}
+
+/*!
+ Sets the port stored in the serial port info instance \a serialPortInfo.
+
+ \sa portName(), QSerialPortInfo
+*/
+void QSerialPort::setPort(const QSerialPortInfo &serialPortInfo)
+{
+ Q_D(QSerialPort);
+ d->systemLocation = serialPortInfo.systemLocation();
+}
+
+/*!
+ Returns the name set by setPort() or passed to the QSerialPort constructor.
+ This name is short, i.e. it is extracted and converted from the internal
+ variable system location of the device. The conversion algorithm is
+ platform specific:
+ \table
+ \header
+ \li Platform
+ \li Brief Description
+ \row
+ \li Windows
+ \li Removes the prefix "\\\\.\\" or "//./" from the system location
+ and returns the remainder of the string.
+ \row
+ \li Windows CE
+ \li Removes the suffix ":" from the system location
+ and returns the remainder of the string.
+ \row
+ \li Symbian
+ \li Returns the system location as it is,
+ as it is equivalent to the port name.
+ \row
+ \li Unix, BSD
+ \li Removes the prefix "/dev/" from the system location
+ and returns the remainder of the string.
+ \endtable
+
+ \sa setPort(), QSerialPortInfo::portName()
+*/
+QString QSerialPort::portName() const
+{
+ Q_D(const QSerialPort);
+ return QSerialPortInfoPrivate::portNameFromSystemLocation(d->systemLocation);
+}
+
+/*!
+ \reimp
+
+ Opens the serial port using OpenMode \a mode, and then returns true if
+ successful; otherwise returns false and sets an error code which can be
+ obtained by calling the error() method.
+
+ \note The method returns false if opening the port is successful, but could
+ not set any of the port settings successfully. In that case, the port is
+ closed automatically not to leave the port around with incorrect settings.
+
+ \warning The \a mode has to be QIODevice::ReadOnly, QIODevice::WriteOnly,
+ or QIODevice::ReadWrite. Other modes are unsupported.
+
+ \sa QIODevice::OpenMode, setPort()
+*/
+bool QSerialPort::open(OpenMode mode)
+{
+ Q_D(QSerialPort);
+
+ if (isOpen()) {
+ setError(QSerialPort::OpenError);
+ return false;
+ }
+
+ // Define while not supported modes.
+ static const OpenMode unsupportedModes = Append | Truncate | Text | Unbuffered;
+ if ((mode & unsupportedModes) || mode == NotOpen) {
+ setError(QSerialPort::UnsupportedOperationError);
+ return false;
+ }
+
+ clearError();
+ if (!d->open(mode))
+ return false;
+
+ if (!d->setBaudRate()
+ || !d->setDataBits(d->dataBits)
+ || !d->setParity(d->parity)
+ || !d->setStopBits(d->stopBits)
+ || !d->setFlowControl(d->flowControl)) {
+ d->close();
+ return false;
+ }
+
+ QIODevice::open(mode);
+ return true;
+}
+
+/*!
+ \reimp
+
+ \note The serial port has to be open before trying to close it; otherwise
+ sets the NotOpenError error code.
+
+ \sa QIODevice::close()
+*/
+void QSerialPort::close()
+{
+ Q_D(QSerialPort);
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ return;
+ }
+
+ QIODevice::close();
+ d->close();
+}
+
+/*!
+ \property QSerialPort::settingsRestoredOnClose
+ \brief the flag which specifies to restore the previous settings when closing
+ the serial port.
+ \obsolete
+
+ If this flag is true, the settings will be restored; otherwise not.
+ The default state of the QSerialPort class is to restore the
+ settings.
+*/
+#if QT_DEPRECATED_SINCE(5,3)
+void QSerialPort::setSettingsRestoredOnClose(bool restore)
+{
+ Q_D(QSerialPort);
+
+ if (d->settingsRestoredOnClose != restore) {
+ d->settingsRestoredOnClose = restore;
+ emit settingsRestoredOnCloseChanged(d->settingsRestoredOnClose);
+ }
+}
+
+bool QSerialPort::settingsRestoredOnClose() const
+{
+ Q_D(const QSerialPort);
+ return d->settingsRestoredOnClose;
+}
+#endif // QT_DEPRECATED_SINCE(5,3)
+/*!
+ \fn void QSerialPort::settingsRestoredOnCloseChanged(bool restore)
+ \obsolete
+
+ This signal is emitted after the flag which specifies to restore the
+ previous settings while closing the serial port has been changed. The new
+ flag which specifies to restore the previous settings while closing the serial
+ port is passed as \a restore.
+
+ \sa QSerialPort::settingsRestoredOnClose
+*/
+
+/*!
+ \property QSerialPort::baudRate
+ \brief the data baud rate for the desired direction
+
+ If the setting is successful or set before opening the port, returns true;
+ otherwise returns false and sets an error code which can be obtained by
+ accessing the value of the QSerialPort::error property. To set the baud
+ rate, use the enumeration QSerialPort::BaudRate or any positive qint32
+ value.
+
+ \note If the setting is set before opening the port, the actual serial port
+ setting is done automatically in the \l{QSerialPort::open()} method right
+ after that the opening of the port succeeds.
+
+ \warning Setting the AllDirections flag is only supported on
+ the Windows, Windows CE, and Symbian platforms.
+
+ \warning Returns equal baud rate in any direction on Windows, Windows CE, and
+ Symbian.
+
+ The default value is Baud9600, i.e. 9600 bits per second.
+*/
+bool QSerialPort::setBaudRate(qint32 baudRate, Directions directions)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen() || d->setBaudRate(baudRate, directions)) {
+ if (directions & QSerialPort::Input) {
+ if (d->inputBaudRate != baudRate)
+ d->inputBaudRate = baudRate;
+ else
+ directions &= ~QSerialPort::Input;
+ }
+
+ if (directions & QSerialPort::Output) {
+ if (d->outputBaudRate != baudRate)
+ d->outputBaudRate = baudRate;
+ else
+ directions &= ~QSerialPort::Output;
+ }
+
+ if (directions)
+ emit baudRateChanged(baudRate, directions);
+
+ return true;
+ }
+
+ return false;
+}
+
+qint32 QSerialPort::baudRate(Directions directions) const
+{
+ Q_D(const QSerialPort);
+ if (directions == QSerialPort::AllDirections)
+ return d->inputBaudRate == d->outputBaudRate ?
+ d->inputBaudRate : -1;
+ return directions & QSerialPort::Input ? d->inputBaudRate : d->outputBaudRate;
+}
+
+/*!
+ \fn void QSerialPort::baudRateChanged(qint32 baudRate, Directions directions)
+
+ This signal is emitted after the baud rate has been changed. The new baud
+ rate is passed as \a baudRate and directions as \a directions.
+
+ \sa QSerialPort::baudRate
+*/
+
+/*!
+ \property QSerialPort::dataBits
+ \brief the data bits in a frame
+
+ If the setting is successful or set before opening the port, returns
+ true; otherwise returns false and sets an error code which can be obtained
+ by accessing the value of the QSerialPort::error property.
+
+ \note If the setting is set before opening the port, the actual serial port
+ setting is done automatically in the \l{QSerialPort::open()} method right
+ after that the opening of the port succeeds.
+
+ The default value is Data8, i.e. 8 data bits.
+*/
+bool QSerialPort::setDataBits(DataBits dataBits)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen() || d->setDataBits(dataBits)) {
+ if (d->dataBits != dataBits) {
+ d->dataBits = dataBits;
+ emit dataBitsChanged(d->dataBits);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+QSerialPort::DataBits QSerialPort::dataBits() const
+{
+ Q_D(const QSerialPort);
+ return d->dataBits;
+}
+
+/*!
+ \fn void QSerialPort::dataBitsChanged(DataBits dataBits)
+
+ This signal is emitted after the data bits in a frame has been changed. The
+ new data bits in a frame is passed as \a dataBits.
+
+ \sa QSerialPort::dataBits
+*/
+
+
+/*!
+ \property QSerialPort::parity
+ \brief the parity checking mode
+
+ If the setting is successful or set before opening the port, returns true;
+ otherwise returns false and sets an error code which can be obtained by
+ accessing the value of the QSerialPort::error property.
+
+ \note If the setting is set before opening the port, the actual serial port
+ setting is done automatically in the \l{QSerialPort::open()} method right
+ after that the opening of the port succeeds.
+
+ The default value is NoParity, i.e. no parity.
+*/
+bool QSerialPort::setParity(Parity parity)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen() || d->setParity(parity)) {
+ if (d->parity != parity) {
+ d->parity = parity;
+ emit parityChanged(d->parity);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+QSerialPort::Parity QSerialPort::parity() const
+{
+ Q_D(const QSerialPort);
+ return d->parity;
+}
+
+/*!
+ \fn void QSerialPort::parityChanged(Parity parity)
+
+ This signal is emitted after the parity checking mode has been changed. The
+ new parity checking mode is passed as \a parity.
+
+ \sa QSerialPort::parity
+*/
+
+/*!
+ \property QSerialPort::stopBits
+ \brief the number of stop bits in a frame
+
+ If the setting is successful or set before opening the port, returns true;
+ otherwise returns false and sets an error code which can be obtained by
+ accessing the value of the QSerialPort::error property.
+
+ \note If the setting is set before opening the port, the actual serial port
+ setting is done automatically in the \l{QSerialPort::open()} method right
+ after that the opening of the port succeeds.
+
+ The default value is OneStop, i.e. 1 stop bit.
+*/
+bool QSerialPort::setStopBits(StopBits stopBits)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen() || d->setStopBits(stopBits)) {
+ if (d->stopBits != stopBits) {
+ d->stopBits = stopBits;
+ emit stopBitsChanged(d->stopBits);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+QSerialPort::StopBits QSerialPort::stopBits() const
+{
+ Q_D(const QSerialPort);
+ return d->stopBits;
+}
+
+/*!
+ \fn void QSerialPort::stopBitsChanged(StopBits stopBits)
+
+ This signal is emitted after the number of stop bits in a frame has been
+ changed. The new number of stop bits in a frame is passed as \a stopBits.
+
+ \sa QSerialPort::stopBits
+*/
+
+/*!
+ \property QSerialPort::flowControl
+ \brief the desired flow control mode
+
+ If the setting is successful or set before opening the port, returns true;
+ otherwise returns false and sets an error code which can be obtained by
+ accessing the value of the QSerialPort::error property.
+
+ \note If the setting is set before opening the port, the actual serial port
+ setting is done automatically in the \l{QSerialPort::open()} method right
+ after that the opening of the port succeeds.
+
+ The default value is NoFlowControl, i.e. no flow control.
+*/
+bool QSerialPort::setFlowControl(FlowControl flowControl)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen() || d->setFlowControl(flowControl)) {
+ if (d->flowControl != flowControl) {
+ d->flowControl = flowControl;
+ emit flowControlChanged(d->flowControl);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+QSerialPort::FlowControl QSerialPort::flowControl() const
+{
+ Q_D(const QSerialPort);
+ return d->flowControl;
+}
+
+/*!
+ \fn void QSerialPort::flowControlChanged(FlowControl flow)
+
+ This signal is emitted after the flow control mode has been changed. The
+ new flow control mode is passed as \a flow.
+
+ \sa QSerialPort::flowControl
+*/
+
+/*!
+ \property QSerialPort::dataTerminalReady
+ \brief the state (high or low) of the line signal DTR
+
+ Returns true on success, false otherwise.
+ If the flag is true then the DTR signal is set to high; otherwise low.
+
+ \note The serial port has to be open before trying to set or get this
+ property; otherwise false is returned and the error code is set to
+ NotOpenError.
+
+ \sa pinoutSignals()
+*/
+bool QSerialPort::setDataTerminalReady(bool set)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ const bool dataTerminalReady = isDataTerminalReady();
+ const bool retval = d->setDataTerminalReady(set);
+ if (retval && (dataTerminalReady != set))
+ emit dataTerminalReadyChanged(set);
+
+ return retval;
+}
+
+bool QSerialPort::isDataTerminalReady()
+{
+ Q_D(QSerialPort);
+ return d->pinoutSignals() & QSerialPort::DataTerminalReadySignal;
+}
+
+/*!
+ \fn void QSerialPort::dataTerminalReadyChanged(bool set)
+
+ This signal is emitted after the state (high or low) of the line signal DTR
+ has been changed. The new the state (high or low) of the line signal DTR is
+ passed as \a set.
+
+ \sa QSerialPort::dataTerminalReady
+*/
+
+/*!
+ \property QSerialPort::requestToSend
+ \brief the state (high or low) of the line signal RTS
+
+ Returns true on success, false otherwise.
+ If the flag is true then the RTS signal is set to high; otherwise low.
+
+ \note The serial port has to be open before trying to set or get this
+ property; otherwise false is returned and the error code is set to
+ NotOpenError.
+
+ \sa pinoutSignals()
+*/
+bool QSerialPort::setRequestToSend(bool set)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ const bool requestToSend = isRequestToSend();
+ const bool retval = d->setRequestToSend(set);
+ if (retval && (requestToSend != set))
+ emit requestToSendChanged(set);
+
+ return retval;
+}
+
+bool QSerialPort::isRequestToSend()
+{
+ Q_D(QSerialPort);
+ return d->pinoutSignals() & QSerialPort::RequestToSendSignal;
+}
+
+/*!
+ \fn void QSerialPort::requestToSendChanged(bool set)
+
+ This signal is emitted after the state (high or low) of the line signal RTS
+ has been changed. The new the state (high or low) of the line signal RTS is
+ passed as \a set.
+
+ \sa QSerialPort::requestToSend
+*/
+
+/*!
+ Returns the state of the line signals in a bitmap format.
+
+ From this result, it is possible to allocate the state of the
+ desired signal by applying a mask "AND", where the mask is
+ the desired enumeration value from QSerialPort::PinoutSignals.
+
+ \note This method performs a system call, thus ensuring that the line signal
+ states are returned properly. This is necessary when the underlying
+ operating systems cannot provide proper notifications about the changes.
+
+ \note The serial port has to be open before trying to get the pinout
+ signals; otherwise returns NoSignal and sets the NotOpenError error code.
+
+ \sa QSerialPort::dataTerminalReady, QSerialPort::requestToSend
+*/
+QSerialPort::PinoutSignals QSerialPort::pinoutSignals()
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return QSerialPort::NoSignal;
+ }
+
+ return d->pinoutSignals();
+}
+
+/*!
+ This function writes as much as possible from the internal write
+ buffer to the underlying serial port without blocking. If any data
+ was written, this function returns true; otherwise returns false.
+
+ Call this function for sending the buffered data immediately to the serial
+ port. The number of bytes successfully written depends on the operating
+ system. In most cases, this function does not need to be called, because the
+ QSerialPort class will start sending data automatically once control is
+ returned to the event loop. In the absence of an event loop, call
+ waitForBytesWritten() instead.
+
+ \note The serial port has to be open before trying to flush any buffered
+ data; otherwise returns false and sets the NotOpenError error code.
+
+ \sa write(), waitForBytesWritten()
+*/
+bool QSerialPort::flush()
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ return d->flush();
+}
+
+/*!
+ Discards all characters from the output or input buffer, depending on
+ given directions \a directions. This includes clearing the internal class buffers and
+ the UART (driver) buffers. Also terminate pending read or write operations.
+ If successful, returns true; otherwise returns false.
+
+ \note The serial port has to be open before trying to clear any buffered
+ data; otherwise returns false and sets the NotOpenError error code.
+*/
+bool QSerialPort::clear(Directions directions)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ if (directions & Input)
+ d->readBuffer.clear();
+ if (directions & Output)
+ d->writeBuffer.clear();
+ return d->clear(directions);
+}
+
+/*!
+ \reimp
+
+ Returns true if no more data is currently available for reading; otherwise
+ returns false.
+
+ This function is most commonly used when reading data from the
+ serial port in a loop. For example:
+
+ \code
+ // This slot is connected to QSerialPort::readyRead()
+ void QSerialPortClass::readyReadSlot()
+ {
+ while (!port.atEnd()) {
+ QByteArray data = port.read(100);
+ ....
+ }
+ }
+ \endcode
+
+ \sa bytesAvailable(), readyRead()
+ */
+bool QSerialPort::atEnd() const
+{
+ Q_D(const QSerialPort);
+ return QIODevice::atEnd() && (!isOpen() || (d->readBuffer.size() == 0));
+}
+
+/*!
+ \property QSerialPort::dataErrorPolicy
+ \brief the error policy for how the process receives characters in the case where
+ a parity error is detected.
+ \obsolete
+
+ If the setting is successful, returns true; otherwise returns false. The
+ default policy set is IgnorePolicy.
+
+ \note The serial port has to be open before trying to set this property;
+ otherwise returns false and sets the NotOpenError error code. This is a bit
+ unusual as opposed to the regular Qt property settings of a class. However,
+ this is a special use case since the property is set through the interaction
+ with the kernel and hardware. Hence, the two scenarios cannot be completely
+ compared to each other.
+*/
+#if QT_DEPRECATED_SINCE(5, 2)
+bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ const bool ret = d->policy == policy || d->setDataErrorPolicy(policy);
+ if (ret && (d->policy != policy)) {
+ d->policy = policy;
+ emit dataErrorPolicyChanged(d->policy);
+ }
+
+ return ret;
+}
+
+QSerialPort::DataErrorPolicy QSerialPort::dataErrorPolicy() const
+{
+ Q_D(const QSerialPort);
+ return d->policy;
+}
+#endif // QT_DEPRECATED_SINCE(5, 2)
+/*!
+ \fn void QSerialPort::dataErrorPolicyChanged(DataErrorPolicy policy)
+ \obsolete
+
+ This signal is emitted after the error policy for how the process receives
+ characters in case of parity error detection has been changed. The new error
+ policy for how the process receives the character in case of parity error
+ detection is passed as \a policy.
+
+ \sa QSerialPort::dataErrorPolicy
+*/
+
+/*!
+ \property QSerialPort::error
+ \brief the error status of the serial port
+
+ The I/O device status returns an error code. For example, if open()
+ returns false, or a read/write operation returns -1, this property can
+ be used to figure out the reason why the operation failed.
+
+ The error code is set to the default QSerialPort::NoError after a call to
+ clearError()
+*/
+QSerialPort::SerialPortError QSerialPort::error() const
+{
+ Q_D(const QSerialPort);
+ return d->error;
+}
+
+void QSerialPort::clearError()
+{
+ setError(QSerialPort::NoError);
+}
+
+/*!
+ \fn void QSerialPort::error(SerialPortError error)
+
+ This signal is emitted after the error has been changed. The new error
+ is passed as \a error.
+
+ \sa QSerialPort::error
+*/
+
+/*!
+ Returns the size of the internal read buffer. This limits the
+ amount of data that the client can receive before calling the read()
+ or readAll() methods.
+
+ A read buffer size of 0 (the default) means that the buffer has
+ no size limit, ensuring that no data is lost.
+
+ \sa setReadBufferSize(), read()
+*/
+qint64 QSerialPort::readBufferSize() const
+{
+ Q_D(const QSerialPort);
+ return d->readBufferMaxSize;
+}
+
+/*!
+ Sets the size of QSerialPort's internal read buffer to be \a
+ size bytes.
+
+ If the buffer size is limited to a certain size, QSerialPort
+ will not buffer more than this size of data. The special case of a buffer
+ size of 0 means that the read buffer is unlimited and all
+ incoming data is buffered. This is the default.
+
+ This option is useful if the data is only read at certain points
+ in time (for instance in a real-time streaming application) or if the serial
+ port should be protected against receiving too much data, which may
+ eventually cause the application to run out of memory.
+
+ \sa readBufferSize(), read()
+*/
+void QSerialPort::setReadBufferSize(qint64 size)
+{
+ Q_D(QSerialPort);
+
+ if (d->readBufferMaxSize == size)
+ return;
+ d->readBufferMaxSize = size;
+}
+
+/*!
+ \reimp
+
+ Always returns true. The serial port is a sequential device.
+*/
+bool QSerialPort::isSequential() const
+{
+ return true;
+}
+
+/*!
+ \reimp
+
+ Returns the number of incoming bytes that are waiting to be read.
+
+ \sa bytesToWrite(), read()
+*/
+qint64 QSerialPort::bytesAvailable() const
+{
+ Q_D(const QSerialPort);
+ return d->readBuffer.size() + QIODevice::bytesAvailable();
+}
+
+/*!
+ \reimp
+
+ Returns the number of bytes that are waiting to be written. The
+ bytes are written when control goes back to the event loop or
+ when flush() is called.
+
+ \sa bytesAvailable(), flush()
+*/
+qint64 QSerialPort::bytesToWrite() const
+{
+ Q_D(const QSerialPort);
+ return d->bytesToWrite() + QIODevice::bytesToWrite();
+}
+
+/*!
+ \reimp
+
+ Returns true if a line of data can be read from the serial port;
+ otherwise returns false.
+
+ \sa readLine()
+*/
+bool QSerialPort::canReadLine() const
+{
+ Q_D(const QSerialPort);
+ const bool hasLine = (d->readBuffer.size() > 0) && d->readBuffer.canReadLine();
+ return hasLine || QIODevice::canReadLine();
+}
+
+/*!
+ \reimp
+
+ This function blocks until new data is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+
+ \sa waitForBytesWritten()
+*/
+bool QSerialPort::waitForReadyRead(int msecs)
+{
+ Q_D(QSerialPort);
+ return d->waitForReadyRead(msecs);
+}
+
+/*!
+ \fn Handle QSerialPort::handle() const
+ \since 5.2
+
+ If the platform is supported and the serial port is open, returns the native
+ serial port handle; otherwise returns -1.
+
+ \warning This function is for expert use only; use it at your own risk.
+ Furthermore, this function carries no compatibility promise between minor
+ Qt releases.
+*/
+
+/*!
+ \reimp
+*/
+bool QSerialPort::waitForBytesWritten(int msecs)
+{
+ Q_D(QSerialPort);
+ return d->waitForBytesWritten(msecs);
+}
+
+/*!
+ Sends a continuous stream of zero bits during a specified period
+ of time \a duration in msec if the terminal is using asynchronous
+ serial data. If successful, returns true; otherwise returns false.
+
+ If the duration is zero then zero bits are transmitted by at least
+ 0.25 seconds, but no more than 0.5 seconds.
+
+ If the duration is non zero then zero bits are transmitted within a certain
+ period of time depending on the implementation.
+
+ \note The serial port has to be open before trying to send a break
+ duration; otherwise returns false and sets the NotOpenError error code.
+
+ \sa setBreakEnabled()
+*/
+bool QSerialPort::sendBreak(int duration)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ return d->sendBreak(duration);
+}
+
+/*!
+ Controls the signal break, depending on the flag \a set.
+ If successful, returns true; otherwise returns false.
+
+ If \a set is true then enables the break transmission; otherwise disables.
+
+ \note The serial port has to be open before trying to set break enabled;
+ otherwise returns false and sets the NotOpenError error code.
+
+ \sa sendBreak()
+*/
+bool QSerialPort::setBreakEnabled(bool set)
+{
+ Q_D(QSerialPort);
+
+ if (!isOpen()) {
+ setError(QSerialPort::NotOpenError);
+ qWarning("%s: device not open", Q_FUNC_INFO);
+ return false;
+ }
+
+ return d->setBreakEnabled(set);
+}
+
+/*!
+ \reimp
+*/
+qint64 QSerialPort::readData(char *data, qint64 maxSize)
+{
+ Q_D(QSerialPort);
+#ifdef Q_OS_ANDROID
+ qint64 retL = d->readBuffer.read(data, maxSize);
+ d->startReadThread();
+ return retL;
+#else
+ return d->readData(data, maxSize);
+#endif
+}
+
+/*!
+ \reimp
+*/
+qint64 QSerialPort::readLineData(char *data, qint64 maxSize)
+{
+#ifdef Q_OS_ANDROID
+ qint64 retL = QIODevice::readLineData(data, maxSize);
+ Q_D(QSerialPort);
+ d->startReadThread();
+ return retL;
+#else
+ return QIODevice::readLineData(data, maxSize);
+#endif
+}
+
+/*!
+ \reimp
+*/
+qint64 QSerialPort::writeData(const char *data, qint64 maxSize)
+{
+ Q_D(QSerialPort);
+ return d->writeData(data, maxSize);
+}
+
+void QSerialPort::setError(QSerialPort::SerialPortError serialPortError, const QString &errorString)
+{
+ Q_D(QSerialPort);
+
+ d->error = serialPortError;
+
+ if (errorString.isNull())
+ setErrorString(qt_error_string(-1));
+ else
+ setErrorString(errorString);
+
+ emit error(serialPortError);
+}
+
+#include "moc_qserialport.cpp"
+
+QT_END_NAMESPACE
diff --git a/libs/qtandroidserialport/src/qserialport.h b/libs/qtandroidserialport/src/qserialport.h
new file mode 100644
index 0000000000000000000000000000000000000000..c637a3f79d3fb7d7efb20bfa6df0cbc8dd4bf965
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialport.h
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov
+** Copyright (C) 2013 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERIALPORT_H
+#define QSERIALPORT_H
+
+#include
+
+QT_BEGIN_NAMESPACE
+
+class QSerialPortInfo;
+class QSerialPortPrivate;
+
+class QSerialPort : public QIODevice
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSerialPort)
+
+ Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate NOTIFY baudRateChanged)
+ Q_PROPERTY(DataBits dataBits READ dataBits WRITE setDataBits NOTIFY dataBitsChanged)
+ Q_PROPERTY(Parity parity READ parity WRITE setParity NOTIFY parityChanged)
+ Q_PROPERTY(StopBits stopBits READ stopBits WRITE setStopBits NOTIFY stopBitsChanged)
+ Q_PROPERTY(FlowControl flowControl READ flowControl WRITE setFlowControl NOTIFY flowControlChanged)
+#if QT_DEPRECATED_SINCE(5, 2)
+ Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy NOTIFY dataErrorPolicyChanged)
+#endif
+ Q_PROPERTY(bool dataTerminalReady READ isDataTerminalReady WRITE setDataTerminalReady NOTIFY dataTerminalReadyChanged)
+ Q_PROPERTY(bool requestToSend READ isRequestToSend WRITE setRequestToSend NOTIFY requestToSendChanged)
+ Q_PROPERTY(SerialPortError error READ error RESET clearError NOTIFY error)
+#if QT_DEPRECATED_SINCE(5, 3)
+ Q_PROPERTY(bool settingsRestoredOnClose READ settingsRestoredOnClose WRITE setSettingsRestoredOnClose NOTIFY settingsRestoredOnCloseChanged)
+#endif
+
+ Q_ENUMS(BaudRate DataBits Parity StopBits FlowControl DataErrorPolicy SerialPortError)
+ Q_FLAGS(Directions PinoutSignals)
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ typedef void* Handle;
+#else
+ typedef int Handle;
+#endif
+
+public:
+
+ enum Direction {
+ Input = 1,
+ Output = 2,
+ AllDirections = Input | Output
+ };
+ Q_DECLARE_FLAGS(Directions, Direction)
+
+ enum BaudRate {
+ Baud1200 = 1200,
+ Baud2400 = 2400,
+ Baud4800 = 4800,
+ Baud9600 = 9600,
+ Baud19200 = 19200,
+ Baud38400 = 38400,
+ Baud57600 = 57600,
+ Baud115200 = 115200,
+ UnknownBaud = -1
+ };
+
+ enum DataBits {
+ Data5 = 5,
+ Data6 = 6,
+ Data7 = 7,
+ Data8 = 8,
+ UnknownDataBits = -1
+ };
+
+ enum Parity {
+ NoParity = 0,
+ EvenParity = 2,
+ OddParity = 3,
+ SpaceParity = 4,
+ MarkParity = 5,
+ UnknownParity = -1
+ };
+
+ enum StopBits {
+ OneStop = 1,
+ OneAndHalfStop = 3,
+ TwoStop = 2,
+ UnknownStopBits = -1
+ };
+
+ enum FlowControl {
+ NoFlowControl,
+ HardwareControl,
+ SoftwareControl,
+ UnknownFlowControl = -1
+ };
+
+ enum PinoutSignal {
+ NoSignal = 0x00,
+ TransmittedDataSignal = 0x01,
+ ReceivedDataSignal = 0x02,
+ DataTerminalReadySignal = 0x04,
+ DataCarrierDetectSignal = 0x08,
+ DataSetReadySignal = 0x10,
+ RingIndicatorSignal = 0x20,
+ RequestToSendSignal = 0x40,
+ ClearToSendSignal = 0x80,
+ SecondaryTransmittedDataSignal = 0x100,
+ SecondaryReceivedDataSignal = 0x200
+ };
+ Q_DECLARE_FLAGS(PinoutSignals, PinoutSignal)
+
+#if QT_DEPRECATED_SINCE(5, 2)
+#if defined _MSC_VER
+#pragma deprecated(UnknownBaud)
+#pragma deprecated(UnknownDataBits)
+#pragma deprecated(UnknownParity)
+#pragma deprecated(UnknownStopBits)
+#pragma deprecated(UnknownFlowControl)
+#pragma deprecated(TransmittedDataSignal)
+#pragma deprecated(ReceivedDataSignal)
+#endif
+#endif
+
+#if QT_DEPRECATED_SINCE(5, 2)
+ enum DataErrorPolicy {
+ SkipPolicy,
+ PassZeroPolicy,
+ IgnorePolicy,
+ StopReceivingPolicy,
+ UnknownPolicy = -1
+ };
+#endif
+
+ enum SerialPortError {
+ NoError,
+ DeviceNotFoundError,
+ PermissionError,
+ OpenError,
+ ParityError,
+ FramingError,
+ BreakConditionError,
+ WriteError,
+ ReadError,
+ ResourceError,
+ UnsupportedOperationError,
+ UnknownError,
+ TimeoutError,
+ NotOpenError
+ };
+
+ explicit QSerialPort(QObject *parent = Q_NULLPTR);
+ explicit QSerialPort(const QString &name, QObject *parent = Q_NULLPTR);
+ explicit QSerialPort(const QSerialPortInfo &info, QObject *parent = Q_NULLPTR);
+ virtual ~QSerialPort();
+
+ void setPortName(const QString &name);
+ QString portName() const;
+
+ void setPort(const QSerialPortInfo &info);
+
+ bool open(OpenMode mode) Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+
+#if QT_DEPRECATED_SINCE(5, 3)
+ QT_DEPRECATED void setSettingsRestoredOnClose(bool restore);
+ QT_DEPRECATED bool settingsRestoredOnClose() const;
+#endif
+
+ bool setBaudRate(qint32 baudRate, Directions directions = AllDirections);
+ qint32 baudRate(Directions directions = AllDirections) const;
+
+ bool setDataBits(DataBits dataBits);
+ DataBits dataBits() const;
+
+ bool setParity(Parity parity);
+ Parity parity() const;
+
+ bool setStopBits(StopBits stopBits);
+ StopBits stopBits() const;
+
+ bool setFlowControl(FlowControl flowControl);
+ FlowControl flowControl() const;
+
+ bool setDataTerminalReady(bool set);
+ bool isDataTerminalReady();
+
+ bool setRequestToSend(bool set);
+ bool isRequestToSend();
+
+ PinoutSignals pinoutSignals();
+
+ bool flush();
+ bool clear(Directions directions = AllDirections);
+ bool atEnd() const Q_DECL_OVERRIDE;
+
+#if QT_DEPRECATED_SINCE(5, 2)
+ QT_DEPRECATED bool setDataErrorPolicy(DataErrorPolicy policy = IgnorePolicy);
+ QT_DEPRECATED DataErrorPolicy dataErrorPolicy() const;
+#endif
+
+ SerialPortError error() const;
+ void clearError();
+
+ qint64 readBufferSize() const;
+ void setReadBufferSize(qint64 size);
+
+ bool isSequential() const Q_DECL_OVERRIDE;
+
+ qint64 bytesAvailable() const Q_DECL_OVERRIDE;
+ qint64 bytesToWrite() const Q_DECL_OVERRIDE;
+ bool canReadLine() const Q_DECL_OVERRIDE;
+
+ bool waitForReadyRead(int msecs) Q_DECL_OVERRIDE;
+ bool waitForBytesWritten(int msecs) Q_DECL_OVERRIDE;
+
+ bool sendBreak(int duration = 0);
+ bool setBreakEnabled(bool set = true);
+
+ Handle handle() const;
+
+Q_SIGNALS:
+ void baudRateChanged(qint32 baudRate, QSerialPort::Directions directions);
+ void dataBitsChanged(QSerialPort::DataBits dataBits);
+ void parityChanged(QSerialPort::Parity parity);
+ void stopBitsChanged(QSerialPort::StopBits stopBits);
+ void flowControlChanged(QSerialPort::FlowControl flowControl);
+ void dataErrorPolicyChanged(QSerialPort::DataErrorPolicy policy);
+ void dataTerminalReadyChanged(bool set);
+ void requestToSendChanged(bool set);
+ void error(QSerialPort::SerialPortError serialPortError);
+ void settingsRestoredOnCloseChanged(bool restore);
+
+protected:
+ qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
+ qint64 readLineData(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
+ qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE;
+
+private:
+ void setError(QSerialPort::SerialPortError error, const QString &errorString = QString());
+
+ QSerialPortPrivate * const d_ptr;
+
+ Q_DISABLE_COPY(QSerialPort)
+
+#if defined (Q_OS_WIN32)
+ Q_PRIVATE_SLOT(d_func(), bool _q_completeAsyncCommunication())
+ Q_PRIVATE_SLOT(d_func(), bool _q_completeAsyncRead())
+ Q_PRIVATE_SLOT(d_func(), bool _q_completeAsyncWrite())
+ Q_PRIVATE_SLOT(d_func(), bool _q_startAsyncWrite())
+#endif
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::PinoutSignals)
+
+QT_END_NAMESPACE
+
+#endif // QSERIALPORT_H
diff --git a/libs/qtandroidserialport/src/qserialport_android.cpp b/libs/qtandroidserialport/src/qserialport_android.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..53b64440d13005b235f10b59245872fde58fb257
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialport_android.cpp
@@ -0,0 +1,867 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov
+** Copyright (C) 2012 Laszlo Papp
+** Copyright (C) 2012 Andre Hartmann
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Written by: S. Michael Goza 2014
+// Adapted for QGC by: Gus Grubba 2015
+
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "qserialport_android_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define BAD_PORT 0
+
+static const char V_jniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"};
+static const char V_TAG[] {"QGC_QSerialPort"};
+
+static void jniDeviceHasDisconnected(JNIEnv *envA, jobject thizA, jint userDataA)
+{
+ Q_UNUSED(envA);
+ Q_UNUSED(thizA);
+ if (userDataA != 0)
+ ((QSerialPortPrivate *)userDataA)->q_ptr->close();
+}
+
+static void jniDeviceNewData(JNIEnv *envA, jobject thizA, jint userDataA, jbyteArray dataA)
+{
+ Q_UNUSED(thizA);
+ if (userDataA != 0)
+ {
+ jbyte *bytesL = envA->GetByteArrayElements(dataA, NULL);
+ jsize lenL = envA->GetArrayLength(dataA);
+ ((QSerialPortPrivate *)userDataA)->newDataArrived((char *)bytesL, lenL);
+ envA->ReleaseByteArrayElements(dataA, bytesL, JNI_ABORT);
+ }
+}
+
+static void jniDeviceException(JNIEnv *envA, jobject thizA, jint userDataA, jstring messageA)
+{
+ Q_UNUSED(thizA);
+ if(userDataA != 0)
+ {
+ const char *stringL = envA->GetStringUTFChars(messageA, NULL);
+ QString strL = QString::fromUtf8(stringL);
+ envA->ReleaseStringUTFChars(messageA, stringL);
+ if(envA->ExceptionCheck())
+ envA->ExceptionClear();
+ ((QSerialPortPrivate *)userDataA)->exceptionArrived(strL);
+ }
+}
+
+QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q)
+ : QSerialPortPrivateData(q)
+ , descriptor(-1)
+ , isCustomBaudRateSupported(false)
+ , emittedBytesWritten(false)
+ , pendingBytesWritten(0)
+ , hasRegisteredFunctions(false)
+ , jniDataBits(8)
+ , jniStopBits(1)
+ , jniParity(0)
+ , internalWriteTimeoutMsec(0)
+ , isReadStopped(true)
+{
+}
+
+bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
+{
+ rwMode = mode;
+ __android_log_print(ANDROID_LOG_INFO, V_TAG, "Opening %s", systemLocation.toLatin1().data());
+
+ QAndroidJniObject jnameL = QAndroidJniObject::fromString(systemLocation);
+ deviceId = QAndroidJniObject::callStaticMethod(
+ V_jniClassName,
+ "open",
+ "(Ljava/lang/String;I)I",
+ jnameL.object(),
+ (jint)this);
+
+ isReadStopped = false;
+
+ if (deviceId == BAD_PORT)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, V_TAG, "Error opening %s", systemLocation.toLatin1().data());
+ q_ptr->setError(QSerialPort::DeviceNotFoundError);
+ return false;
+ }
+
+ descriptor = QAndroidJniObject::callStaticMethod(
+ V_jniClassName,
+ "getDeviceHandle",
+ "(I)I",
+ deviceId);
+
+ if (!hasRegisteredFunctions)
+ {
+ // REGISTER THE C++ FUNCTION WITH JNI
+ QAndroidJniEnvironment envL;
+
+ JNINativeMethod methodsL[] {
+ {"nativeDeviceHasDisconnected", "(I)V", reinterpret_cast(jniDeviceHasDisconnected)},
+ {"nativeDeviceNewData", "(I[B)V", reinterpret_cast(jniDeviceNewData)},
+ {"nativeDeviceException", "(ILjava/lang/String;)V", reinterpret_cast(jniDeviceException)}
+ };
+
+ QAndroidJniObject javaClassL(V_jniClassName);
+ jclass objectClassL = envL->GetObjectClass(javaClassL.object());
+ jint valL = envL->RegisterNatives(objectClassL, methodsL, sizeof(methodsL) / sizeof(methodsL[0]));
+ envL->DeleteLocalRef(objectClassL);
+ hasRegisteredFunctions = true;
+
+ if (envL->ExceptionCheck())
+ envL->ExceptionClear();
+
+ if(valL < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, V_TAG, "Error registering methods");
+ q_ptr->setError(QSerialPort::OpenError);
+ return false;
+ }
+ }
+
+ if (rwMode == QIODevice::WriteOnly)
+ stopReadThread();
+
+ return true;
+}
+
+void QSerialPortPrivate::close()
+{
+ if (deviceId == BAD_PORT)
+ return;
+
+ __android_log_print(ANDROID_LOG_INFO, V_TAG, "Closing %s", systemLocation.toLatin1().data());
+ jboolean resultL = QAndroidJniObject::callStaticMethod(
+ V_jniClassName,
+ "close",
+ "(I)Z",
+ deviceId);
+
+ descriptor = -1;
+ isCustomBaudRateSupported = false;
+ pendingBytesWritten = 0;
+ deviceId = BAD_PORT;
+
+ if (!resultL)
+ q_ptr->setErrorString(QStringLiteral("Closing device failed"));
+}
+
+bool QSerialPortPrivate::setParameters(int baudRateA, int dataBitsA, int stopBitsA, int parityA)
+{
+ if (deviceId == BAD_PORT)
+ {
+ q_ptr->setError(QSerialPort::NotOpenError);
+ return false;
+ }
+
+ jboolean resultL = QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "setParameters",
+ "(IIIII)Z",
+ deviceId,
+ baudRateA,
+ dataBitsA,
+ stopBitsA,
+ parityA);
+
+ if(resultL)
+ {
+ // SET THE JNI VALUES TO WHAT WAS SENT
+ inputBaudRate = outputBaudRate = baudRateA;
+ jniDataBits = dataBitsA;
+ jniStopBits = stopBitsA;
+ jniParity = parityA;
+ }
+
+ return resultL;
+}
+
+
+
+void QSerialPortPrivate::stopReadThread()
+{
+ if (isReadStopped)
+ return;
+
+ QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "stopIoManager",
+ "(I)V",
+ deviceId);
+ isReadStopped = true;
+}
+
+
+
+void QSerialPortPrivate::startReadThread()
+{
+ if (!isReadStopped)
+ return;
+
+ QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "startIoManager",
+ "(I)V",
+ deviceId);
+ isReadStopped = false;
+}
+
+
+
+
+
+QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
+{
+ return QSerialPort::NoSignal;
+}
+
+
+
+
+bool QSerialPortPrivate::setDataTerminalReady(bool set)
+{
+ if (deviceId == BAD_PORT)
+ {
+ q_ptr->setError(QSerialPort::NotOpenError);
+ return false;
+ }
+
+ return QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "setDataTerminalReady",
+ "(IZ)Z",
+ deviceId,
+ set);
+}
+
+
+
+
+bool QSerialPortPrivate::setRequestToSend(bool set)
+{
+ if (deviceId == BAD_PORT)
+ {
+ q_ptr->setError(QSerialPort::NotOpenError);
+ return false;
+ }
+
+ return QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "setRequestToSend",
+ "(IZ)Z",
+ deviceId,
+ set);
+}
+
+
+
+
+bool QSerialPortPrivate::flush()
+{
+ return writeDataOneShot();
+}
+
+
+
+
+bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
+{
+ if (deviceId == BAD_PORT)
+ {
+ q_ptr->setError(QSerialPort::NotOpenError);
+ return false;
+ }
+
+ bool inputL = false;
+ bool outputL = false;
+
+ if (directions == QSerialPort::AllDirections)
+ inputL = outputL = true;
+ else
+ {
+ if (directions & QSerialPort::Input)
+ inputL = true;
+
+ if (directions & QSerialPort::Output)
+ outputL = true;
+ }
+
+ return QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "purgeBuffers",
+ "(IZZ)Z",
+ deviceId,
+ inputL,
+ outputL);
+}
+
+
+
+
+bool QSerialPortPrivate::sendBreak(int duration)
+{
+ Q_UNUSED(duration);
+ return true;
+}
+
+
+
+
+bool QSerialPortPrivate::setBreakEnabled(bool set)
+{
+ Q_UNUSED(set);
+ return true;
+}
+
+
+
+
+void QSerialPortPrivate::startWriting()
+{
+ writeDataOneShot();
+}
+
+
+
+
+bool QSerialPortPrivate::waitForReadyRead(int msecs)
+{
+ int origL = readBuffer.size();
+
+ if (origL > 0)
+ return true;
+
+ for (int iL=0; iLpolicy = policy;
+ return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void QSerialPortPrivate::newDataArrived(char *bytesA, int lengthA)
+{
+ Q_Q(QSerialPort);
+
+ int bytesToReadL = lengthA;
+
+ // Always buffered, read data from the port into the read buffer
+ if (readBufferMaxSize && (bytesToReadL > (readBufferMaxSize - readBuffer.size()))) {
+ bytesToReadL = readBufferMaxSize - readBuffer.size();
+ if (bytesToReadL <= 0) {
+ // Buffer is full. User must read data from the buffer
+ // before we can read more from the port.
+ stopReadThread();
+ return;
+ }
+ }
+
+ char *ptr = readBuffer.reserve(bytesToReadL);
+ memcpy(ptr, bytesA, bytesToReadL);
+
+ emit q->readyRead();
+}
+
+
+
+void QSerialPortPrivate::exceptionArrived(QString strA)
+{
+ q_ptr->setErrorString(strA);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool QSerialPortPrivate::writeDataOneShot()
+{
+ Q_Q(QSerialPort);
+
+ pendingBytesWritten = -1;
+
+ while (!writeBuffer.isEmpty())
+ {
+ pendingBytesWritten = writeToPort(writeBuffer.readPointer(), writeBuffer.nextDataBlockSize());
+
+ if (pendingBytesWritten <= 0)
+ {
+ QSerialPort::SerialPortError errorL = decodeSystemError();
+ if (errorL != QSerialPort::ResourceError)
+ errorL = QSerialPort::WriteError;
+ q->setError(errorL);
+ return false;
+ }
+
+ writeBuffer.free(pendingBytesWritten);
+
+ emit q->bytesWritten(pendingBytesWritten);
+ }
+
+ return (pendingBytesWritten < 0)? false: true;
+}
+
+
+
+QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const
+{
+ QSerialPort::SerialPortError error;
+ switch (errno) {
+ case ENODEV:
+ error = QSerialPort::DeviceNotFoundError;
+ break;
+ case EACCES:
+ error = QSerialPort::PermissionError;
+ break;
+ case EBUSY:
+ error = QSerialPort::PermissionError;
+ break;
+ case EAGAIN:
+ error = QSerialPort::ResourceError;
+ break;
+ case EIO:
+ error = QSerialPort::ResourceError;
+ break;
+ case EBADF:
+ error = QSerialPort::ResourceError;
+ break;
+ default:
+ error = QSerialPort::UnknownError;
+ break;
+ }
+ return error;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
+{
+ if (deviceId == BAD_PORT)
+ {
+ q_ptr->setError(QSerialPort::NotOpenError);
+ return 0;
+ }
+
+ QAndroidJniEnvironment envL;
+ jbyteArray jarrayL = envL->NewByteArray(maxSize);
+ envL->SetByteArrayRegion(jarrayL, 0, maxSize, (jbyte *)data);
+ int resultL = QAndroidJniObject::callStaticMethod(V_jniClassName,
+ "write",
+ "(I[BI)I",
+ deviceId,
+ jarrayL,
+ internalWriteTimeoutMsec);
+
+ if (envL->ExceptionCheck())
+ {
+ envL->ExceptionClear();
+ q_ptr->setErrorString(QStringLiteral("Writing to the device threw an exception"));
+ envL->DeleteLocalRef(jarrayL);
+ return 0;
+ }
+
+ envL->DeleteLocalRef(jarrayL);
+
+ return resultL;
+}
+
+
+
+
+static inline bool evenParity(quint8 c)
+{
+ c ^= c >> 4; //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0)
+ c ^= c >> 2; //[(c7 ^ c3)(c5 ^ c1)][(c6 ^ c2)(c4 ^ c0)]
+ c ^= c >> 1;
+ return c & 1; //(c7 ^ c3)(c5 ^ c1)(c6 ^ c2)(c4 ^ c0)
+}
+
+typedef QMap BaudRateMap;
+
+// The OS specific defines can be found in termios.h
+
+static const BaudRateMap createStandardBaudRateMap()
+{
+ BaudRateMap baudRateMap;
+
+#ifdef B50
+ baudRateMap.insert(50, B50);
+#endif
+
+#ifdef B75
+ baudRateMap.insert(75, B75);
+#endif
+
+#ifdef B110
+ baudRateMap.insert(110, B110);
+#endif
+
+#ifdef B134
+ baudRateMap.insert(134, B134);
+#endif
+
+#ifdef B150
+ baudRateMap.insert(150, B150);
+#endif
+
+#ifdef B200
+ baudRateMap.insert(200, B200);
+#endif
+
+#ifdef B300
+ baudRateMap.insert(300, B300);
+#endif
+
+#ifdef B600
+ baudRateMap.insert(600, B600);
+#endif
+
+#ifdef B1200
+ baudRateMap.insert(1200, B1200);
+#endif
+
+#ifdef B1800
+ baudRateMap.insert(1800, B1800);
+#endif
+
+#ifdef B2400
+ baudRateMap.insert(2400, B2400);
+#endif
+
+#ifdef B4800
+ baudRateMap.insert(4800, B4800);
+#endif
+
+#ifdef B7200
+ baudRateMap.insert(7200, B7200);
+#endif
+
+#ifdef B9600
+ baudRateMap.insert(9600, B9600);
+#endif
+
+#ifdef B14400
+ baudRateMap.insert(14400, B14400);
+#endif
+
+#ifdef B19200
+ baudRateMap.insert(19200, B19200);
+#endif
+
+#ifdef B28800
+ baudRateMap.insert(28800, B28800);
+#endif
+
+#ifdef B38400
+ baudRateMap.insert(38400, B38400);
+#endif
+
+#ifdef B57600
+ baudRateMap.insert(57600, B57600);
+#endif
+
+#ifdef B76800
+ baudRateMap.insert(76800, B76800);
+#endif
+
+#ifdef B115200
+ baudRateMap.insert(115200, B115200);
+#endif
+
+#ifdef B230400
+ baudRateMap.insert(230400, B230400);
+#endif
+
+#ifdef B460800
+ baudRateMap.insert(460800, B460800);
+#endif
+
+#ifdef B500000
+ baudRateMap.insert(500000, B500000);
+#endif
+
+#ifdef B576000
+ baudRateMap.insert(576000, B576000);
+#endif
+
+#ifdef B921600
+ baudRateMap.insert(921600, B921600);
+#endif
+
+#ifdef B1000000
+ baudRateMap.insert(1000000, B1000000);
+#endif
+
+#ifdef B1152000
+ baudRateMap.insert(1152000, B1152000);
+#endif
+
+#ifdef B1500000
+ baudRateMap.insert(1500000, B1500000);
+#endif
+
+#ifdef B2000000
+ baudRateMap.insert(2000000, B2000000);
+#endif
+
+#ifdef B2500000
+ baudRateMap.insert(2500000, B2500000);
+#endif
+
+#ifdef B3000000
+ baudRateMap.insert(3000000, B3000000);
+#endif
+
+#ifdef B3500000
+ baudRateMap.insert(3500000, B3500000);
+#endif
+
+#ifdef B4000000
+ baudRateMap.insert(4000000, B4000000);
+#endif
+
+ return baudRateMap;
+}
+
+
+
+
+static const BaudRateMap& standardBaudRateMap()
+{
+ static const BaudRateMap baudRateMap = createStandardBaudRateMap();
+ return baudRateMap;
+}
+
+
+
+
+qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting)
+{
+ return standardBaudRateMap().key(setting);
+}
+
+
+
+
+qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
+{
+ return standardBaudRateMap().value(baudRate);
+}
+
+
+
+
+QList QSerialPortPrivate::standardBaudRates()
+{
+ return standardBaudRateMap().keys();
+}
+
+
+
+
+QSerialPort::Handle QSerialPort::handle() const
+{
+ Q_D(const QSerialPort);
+ return d->descriptor;
+}
+
+qint64 QSerialPortPrivate::bytesToWrite() const
+{
+ return writeBuffer.size();
+}
+
+qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
+{
+ return writeToPort(data, maxSize);
+}
+
+QT_END_NAMESPACE
+
diff --git a/libs/qtandroidserialport/src/qserialport_android_p.h b/libs/qtandroidserialport/src/qserialport_android_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..f105c1fd74f0441ede8327a2b9bd297aa5bef232
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialport_android_p.h
@@ -0,0 +1,133 @@
+#ifndef QSERIALPORT_ANDROID_P_H
+#define QSERIALPORT_ANDROID_P_H
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov
+** Copyright (C) 2012 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qserialport_p.h"
+
+#include
+#include
+#include
+#include
+
+
+QT_BEGIN_NAMESPACE
+
+class QSerialPortPrivate : public QSerialPortPrivateData
+{
+ Q_DECLARE_PUBLIC(QSerialPort)
+
+public:
+ QSerialPortPrivate(QSerialPort *q);
+
+ bool open(QIODevice::OpenMode mode);
+ void close();
+
+ QSerialPort::PinoutSignals pinoutSignals();
+
+ bool setDataTerminalReady(bool set);
+ bool setRequestToSend(bool set);
+
+ bool flush();
+ bool clear(QSerialPort::Directions directions);
+
+ bool sendBreak(int duration);
+ bool setBreakEnabled(bool set);
+
+ void startWriting();
+
+ bool waitForReadyRead(int msecs);
+ bool waitForBytesWritten(int msecs);
+
+ bool setBaudRate();
+ bool setBaudRate(qint32 baudRate, QSerialPort::Directions directions);
+ bool setDataBits(QSerialPort::DataBits dataBits);
+ bool setParity(QSerialPort::Parity parity);
+ bool setStopBits(QSerialPort::StopBits stopBits);
+ bool setFlowControl(QSerialPort::FlowControl flowControl);
+ bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy);
+
+ bool startAsyncWrite();
+ bool completeAsyncWrite();
+ void newDataArrived(char *bytesA, int lengthA);
+ void exceptionArrived(QString strA);
+
+ void stopReadThread();
+ void startReadThread();
+ qint64 bytesToWrite() const;
+ qint64 writeData(const char *data, qint64 maxSize);
+
+ static qint32 baudRateFromSetting(qint32 setting);
+ static qint32 settingFromBaudRate(qint32 baudRate);
+
+ static QList standardBaudRates();
+
+ int descriptor;
+ bool isCustomBaudRateSupported;
+
+ bool emittedBytesWritten;
+
+ qint64 pendingBytesWritten;
+
+private:
+ QIODevice::OpenMode rwMode;
+ int deviceId;
+ bool hasRegisteredFunctions;
+ int jniDataBits;
+ int jniStopBits;
+ int jniParity;
+ qint64 internalWriteTimeoutMsec;
+ bool isReadStopped;
+
+ bool setParameters(int baudRateA, int dataBitsA, int stopBitsA, int parityA);
+
+ QSerialPort::SerialPortError decodeSystemError() const;
+
+ qint64 writeToPort(const char *data, qint64 maxSize);
+
+ bool writeDataOneShot();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSERIALPORT_ANDROID_P_H
+
diff --git a/libs/qtandroidserialport/src/qserialport_p.h b/libs/qtandroidserialport/src/qserialport_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ba91b9b282197380850f913ab708a685de6049d
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialport_p.h
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov
+** Copyright (C) 2011 Sergey Belyashov
+** Copyright (C) 2012 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERIALPORT_P_H
+#define QSERIALPORT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qserialport.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGCRingBuffer
+{
+public:
+ explicit inline QGCRingBuffer(int growth = 4096) :
+ head(0), tail(0), tailBuffer(0), basicBlockSize(growth), bufferSize(0) {
+ buffers.append(QByteArray());
+ }
+
+ inline int nextDataBlockSize() const {
+ return (tailBuffer == 0 ? tail : buffers.first().size()) - head;
+ }
+
+ inline const char *readPointer() const {
+ return buffers.isEmpty() ? 0 : (buffers.first().constData() + head);
+ }
+
+ // access the bytes at a specified position
+ // the out-variable length will contain the amount of bytes readable
+ // from there, e.g. the amount still the same QByteArray
+ inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const {
+ if (pos >= 0) {
+ pos += head;
+ for (int i = 0; i < buffers.size(); ++i) {
+ length = (i == tailBuffer ? tail : buffers[i].size());
+ if (length > pos) {
+ length -= pos;
+ return buffers[i].constData() + pos;
+ }
+ pos -= length;
+ }
+ }
+
+ length = 0;
+ return 0;
+ }
+
+ inline void free(int bytes) {
+ while (bytes > 0) {
+ int blockSize = buffers.first().size() - head;
+
+ if (tailBuffer == 0 || blockSize > bytes) {
+ bufferSize -= bytes;
+ if (bufferSize <= 0)
+ clear(); // try to minify/squeeze us
+ else
+ head += bytes;
+ return;
+ }
+
+ bufferSize -= blockSize;
+ bytes -= blockSize;
+ buffers.removeFirst();
+ --tailBuffer;
+ head = 0;
+ }
+ }
+
+ inline char *reserve(int bytes) {
+ if (bytes <= 0)
+ return 0;
+
+ // if need buffer reallocation
+ if (tail + bytes > buffers.last().size()) {
+ if (tail >= basicBlockSize) {
+ // shrink this buffer to its current size
+ buffers.last().resize(tail);
+
+ // create a new QByteArray
+ buffers.append(QByteArray());
+ ++tailBuffer;
+ tail = 0;
+ }
+ buffers.last().resize(qMax(basicBlockSize, tail + bytes));
+ }
+
+ char *writePtr = buffers.last().data() + tail;
+ bufferSize += bytes;
+ tail += bytes;
+ return writePtr;
+ }
+
+ inline void truncate(int pos) {
+ if (pos < size())
+ chop(size() - pos);
+ }
+
+ inline void chop(int bytes) {
+ while (bytes > 0) {
+ if (tailBuffer == 0 || tail > bytes) {
+ bufferSize -= bytes;
+ if (bufferSize <= 0)
+ clear(); // try to minify/squeeze us
+ else
+ tail -= bytes;
+ return;
+ }
+
+ bufferSize -= tail;
+ bytes -= tail;
+ buffers.removeLast();
+ --tailBuffer;
+ tail = buffers.last().size();
+ }
+ }
+
+ inline bool isEmpty() const {
+ return tailBuffer == 0 && tail == 0;
+ }
+
+ inline int getChar() {
+ if (isEmpty())
+ return -1;
+ char c = *readPointer();
+ free(1);
+ return int(uchar(c));
+ }
+
+ inline void putChar(char c) {
+ char *ptr = reserve(1);
+ *ptr = c;
+ }
+
+ inline void ungetChar(char c) {
+ --head;
+ if (head < 0) {
+ buffers.prepend(QByteArray());
+ buffers.first().resize(basicBlockSize);
+ head = basicBlockSize - 1;
+ ++tailBuffer;
+ }
+ buffers.first()[head] = c;
+ ++bufferSize;
+ }
+
+ inline int size() const {
+ return bufferSize;
+ }
+
+ inline void clear() {
+ buffers.erase(buffers.begin() + 1, buffers.end());
+ buffers.first().clear();
+
+ head = tail = 0;
+ tailBuffer = 0;
+ bufferSize = 0;
+ }
+
+ inline int indexOf(char c) const {
+ int index = 0;
+ int j = head;
+ for (int i = 0; i < buffers.size(); ++i) {
+ const char *ptr = buffers[i].constData() + j;
+ j = index + (i == tailBuffer ? tail : buffers[i].size()) - j;
+
+ while (index < j) {
+ if (*ptr++ == c)
+ return index;
+ ++index;
+ }
+ j = 0;
+ }
+ return -1;
+ }
+
+ inline int indexOf(char c, int maxLength) const {
+ int index = 0;
+ int j = head;
+ for (int i = 0; index < maxLength && i < buffers.size(); ++i) {
+ const char *ptr = buffers[i].constData() + j;
+ j = qMin(index + (i == tailBuffer ? tail : buffers[i].size()) - j, maxLength);
+
+ while (index < j) {
+ if (*ptr++ == c)
+ return index;
+ ++index;
+ }
+ j = 0;
+ }
+ return -1;
+ }
+
+ inline int read(char *data, int maxLength) {
+ int bytesToRead = qMin(size(), maxLength);
+ int readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize());
+ if (data)
+ memcpy(data + readSoFar, readPointer(), bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ free(bytesToReadFromThisBlock);
+ }
+ return readSoFar;
+ }
+
+ // read an unspecified amount (will read the first buffer)
+ inline QByteArray read() {
+ if (bufferSize == 0)
+ return QByteArray();
+
+ QByteArray qba(buffers.takeFirst());
+
+ qba.reserve(0); // avoid that resizing needlessly reallocates
+ if (tailBuffer == 0) {
+ qba.resize(tail);
+ tail = 0;
+ buffers.append(QByteArray());
+ } else {
+ --tailBuffer;
+ }
+ qba.remove(0, head); // does nothing if head is 0
+ head = 0;
+ bufferSize -= qba.size();
+ return qba;
+ }
+
+ // append a new buffer to the end
+ inline void append(const QByteArray &qba) {
+ if (tail == 0) {
+ buffers.last() = qba;
+ } else {
+ buffers.last().resize(tail);
+ buffers.append(qba);
+ ++tailBuffer;
+ }
+ tail = qba.size();
+ bufferSize += tail;
+ }
+
+ inline int skip(int length) {
+ return read(0, length);
+ }
+
+ inline int readLine(char *data, int maxLength) {
+ if (!data || --maxLength <= 0)
+ return -1;
+
+ int i = indexOf('\n', maxLength);
+ i = read(data, i >= 0 ? (i + 1) : maxLength);
+
+ // Terminate it.
+ data[i] = '\0';
+ return i;
+ }
+
+ inline bool canReadLine() const {
+ return indexOf('\n') >= 0;
+ }
+
+private:
+ QList buffers;
+ int head, tail;
+ int tailBuffer; // always buffers.size() - 1
+ const int basicBlockSize;
+ int bufferSize;
+};
+
+class QSerialPortPrivateData
+{
+public:
+ enum IoConstants {
+ ReadChunkSize = 512
+ };
+
+ QSerialPortPrivateData(QSerialPort *q);
+ int timeoutValue(int msecs, int elapsed);
+
+ qint64 readBufferMaxSize;
+ QGCRingBuffer readBuffer;
+ QGCRingBuffer writeBuffer;
+ QSerialPort::SerialPortError error;
+ QString systemLocation;
+ qint32 inputBaudRate;
+ qint32 outputBaudRate;
+ QSerialPort::DataBits dataBits;
+ QSerialPort::Parity parity;
+ QSerialPort::StopBits stopBits;
+ QSerialPort::FlowControl flowControl;
+ QSerialPort::DataErrorPolicy policy;
+ bool settingsRestoredOnClose;
+ QSerialPort * const q_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSERIALPORT_P_H
diff --git a/libs/qtandroidserialport/src/qserialportinfo.cpp b/libs/qtandroidserialport/src/qserialportinfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..26b275d6d398f8f2265a741a7dd86978f6243996
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialportinfo.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov
+** Copyright (C) 2011 Sergey Belyashov
+** Copyright (C) 2012 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qserialportinfo.h"
+#include "qserialportinfo_p.h"
+#include "qserialport.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \class QSerialPortInfo
+
+ \brief Provides information about existing serial ports.
+
+ \ingroup serialport-main
+ \inmodule QtSerialPort
+ \since 5.1
+
+ Use the static functions to generate a list of QSerialPortInfo
+ objects. Each QSerialPortInfo object in the list represents a single
+ serial port and can be queried for the port name, system location,
+ description, and manufacturer. The QSerialPortInfo class can also be
+ used as an input parameter for the setPort() method of the QSerialPort
+ class.
+
+ \sa QSerialPort
+*/
+
+/*!
+ Constructs an empty QSerialPortInfo object.
+
+ \sa isNull()
+*/
+QSerialPortInfo::QSerialPortInfo()
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QSerialPortInfo::QSerialPortInfo(const QSerialPortInfo &other)
+ : d_ptr(other.d_ptr ? new QSerialPortInfoPrivate(*other.d_ptr) : Q_NULLPTR)
+{
+}
+
+/*!
+ Constructs a QSerialPortInfo object from serial \a port.
+*/
+QSerialPortInfo::QSerialPortInfo(const QSerialPort &port)
+{
+ foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) {
+ if (port.portName() == serialPortInfo.portName()) {
+ *this = serialPortInfo;
+ break;
+ }
+ }
+}
+
+/*!
+ Constructs a QSerialPortInfo object from serial port \a name.
+
+ This constructor finds the relevant serial port among the available ones
+ according to the port name \a name, and constructs the serial port info
+ instance for that port.
+*/
+QSerialPortInfo::QSerialPortInfo(const QString &name)
+{
+ foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) {
+ if (name == serialPortInfo.portName()) {
+ *this = serialPortInfo;
+ break;
+ }
+ }
+}
+
+QSerialPortInfo::QSerialPortInfo(const QSerialPortInfoPrivate &dd)
+ : d_ptr(new QSerialPortInfoPrivate(dd))
+{
+}
+
+/*!
+ Destroys the QSerialPortInfo object. References to the values in the
+ object become invalid.
+*/
+QSerialPortInfo::~QSerialPortInfo()
+{
+}
+
+/*! \fn void QSerialPortInfo::swap(QSerialPortInfo &other)
+
+ Swaps QSerialPortInfo \a other with this QSerialPortInfo. This operation is
+ very fast and never fails.
+*/
+void QSerialPortInfo::swap(QSerialPortInfo &other)
+{
+ d_ptr.swap(other.d_ptr);
+}
+
+/*!
+ Sets the QSerialPortInfo object to be equal to \a other.
+*/
+QSerialPortInfo& QSerialPortInfo::operator=(const QSerialPortInfo &other)
+{
+ QSerialPortInfo(other).swap(*this);
+ return *this;
+}
+
+/*!
+ Returns the name of the serial port.
+
+ \sa systemLocation()
+*/
+QString QSerialPortInfo::portName() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? QString() : d->portName;
+}
+
+/*!
+ Returns the system location of the serial port.
+
+ \sa portName()
+*/
+QString QSerialPortInfo::systemLocation() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? QString() : d->device;
+}
+
+/*!
+ Returns the description string of the serial port,
+ if available; otherwise returns an empty string.
+
+ \sa manufacturer(), serialNumber()
+*/
+QString QSerialPortInfo::description() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? QString() : d->description;
+}
+
+/*!
+ Returns the manufacturer string of the serial port,
+ if available; otherwise returns an empty string.
+
+ \sa description(), serialNumber()
+*/
+QString QSerialPortInfo::manufacturer() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? QString() : d->manufacturer;
+}
+
+/*!
+ \since 5.3
+
+ Returns the serial number string of the serial port,
+ if available; otherwise returns an empty string.
+
+ \note The serial number may include letters.
+
+ \sa description(), manufacturer()
+*/
+QString QSerialPortInfo::serialNumber() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? QString() : d->serialNumber;
+}
+
+/*!
+ Returns the 16-bit vendor number for the serial port, if available;
+ otherwise returns zero.
+
+ \sa hasVendorIdentifier(), productIdentifier(), hasProductIdentifier()
+*/
+quint16 QSerialPortInfo::vendorIdentifier() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? 0 : d->vendorIdentifier;
+}
+
+/*!
+ Returns the 16-bit product number for the serial port, if available;
+ otherwise returns zero.
+
+ \sa hasProductIdentifier(), vendorIdentifier(), hasVendorIdentifier()
+*/
+quint16 QSerialPortInfo::productIdentifier() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? 0 : d->productIdentifier;
+}
+
+/*!
+ Returns true if there is a valid 16-bit vendor number present; otherwise
+ returns false.
+
+ \sa vendorIdentifier(), productIdentifier(), hasProductIdentifier()
+*/
+bool QSerialPortInfo::hasVendorIdentifier() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? false : d->hasVendorIdentifier;
+}
+
+/*!
+ Returns true if there is a valid 16-bit product number present; otherwise
+ returns false.
+
+ \sa productIdentifier(), vendorIdentifier(), hasVendorIdentifier()
+*/
+bool QSerialPortInfo::hasProductIdentifier() const
+{
+ Q_D(const QSerialPortInfo);
+ return !d ? false : d->hasProductIdentifier;
+}
+
+/*!
+ \fn bool QSerialPortInfo::isNull() const
+
+ Returns whether this QSerialPortInfo object holds a
+ serial port definition.
+
+ \sa isBusy()
+*/
+
+/*!
+ \fn bool QSerialPortInfo::isBusy() const
+
+ Returns true if serial port is busy;
+ otherwise returns false.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn bool QSerialPortInfo::isValid() const
+ \obsolete
+
+ Returns true if serial port is present on system;
+ otherwise returns false.
+
+ \sa isNull(), isBusy()
+*/
+
+/*!
+ \fn QList QSerialPortInfo::standardBaudRates()
+
+ Returns a list of available standard baud rates supported by
+ the current serial port.
+*/
+
+/*!
+ \fn QList QSerialPortInfo::availablePorts()
+
+ Returns a list of available serial ports on the system.
+*/
+
+QT_END_NAMESPACE
diff --git a/libs/qtandroidserialport/src/qserialportinfo.h b/libs/qtandroidserialport/src/qserialportinfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..6fe1662e822be6403f0ab740639051dc176e7a3f
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialportinfo.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Denis Shienkov
+** Copyright (C) 2012 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERIALPORTINFO_H
+#define QSERIALPORTINFO_H
+
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+
+class QSerialPort;
+class QSerialPortInfoPrivate;
+class QSerialPortInfoPrivateDeleter;
+
+class QSerialPortInfo
+{
+ Q_DECLARE_PRIVATE(QSerialPortInfo)
+public:
+ QSerialPortInfo();
+ explicit QSerialPortInfo(const QSerialPort &port);
+ explicit QSerialPortInfo(const QString &name);
+ QSerialPortInfo(const QSerialPortInfo &other);
+ ~QSerialPortInfo();
+
+ QSerialPortInfo& operator=(const QSerialPortInfo &other);
+ void swap(QSerialPortInfo &other);
+
+ QString portName() const;
+ QString systemLocation() const;
+ QString description() const;
+ QString manufacturer() const;
+ QString serialNumber() const;
+
+ quint16 vendorIdentifier() const;
+ quint16 productIdentifier() const;
+
+ bool hasVendorIdentifier() const;
+ bool hasProductIdentifier() const;
+
+ bool isNull() const;
+ bool isBusy() const;
+#if QT_DEPRECATED_SINCE(5, 2)
+ QT_DEPRECATED bool isValid() const;
+#endif
+
+ static QList standardBaudRates();
+ static QList availablePorts();
+
+ QScopedPointer d_ptr;
+
+private:
+ QSerialPortInfo(const QSerialPortInfoPrivate &dd);
+ friend QList availablePortsByUdev(bool &ok);
+ friend QList availablePortsBySysfs(bool &ok);
+ friend QList availablePortsByFiltersOfDevices(bool &ok);
+};
+
+inline bool QSerialPortInfo::isNull() const
+{ return !d_ptr; }
+
+QT_END_NAMESPACE
+
+#endif // QSERIALPORTINFO_H
diff --git a/libs/qtandroidserialport/src/qserialportinfo_android.cpp b/libs/qtandroidserialport/src/qserialportinfo_android.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..50db905fce310dc969b7810b4461da5066df3d77
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialportinfo_android.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov
+** Copyright (C) 2011 Sergey Belyashov
+** Copyright (C) 2012 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qserialportinfo.h"
+#include "qserialportinfo_p.h"
+#include "qserialport_android_p.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+QT_BEGIN_NAMESPACE
+static const char V_jniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"};
+static const char V_TAG[] {"QGC_QSerialPortInfo"};
+
+QList availablePortsByFiltersOfDevices()
+{
+ QList serialPortInfoList;
+
+ __android_log_print(ANDROID_LOG_INFO, V_TAG, "Collecting device list");
+ QAndroidJniObject resultL = QAndroidJniObject::callStaticObjectMethod(
+ V_jniClassName,
+ "availableDevicesInfo",
+ "()[Ljava/lang/String;");
+
+ if (!resultL.isValid()) {
+ __android_log_print(ANDROID_LOG_ERROR, V_TAG, "Error from availableDevicesInfo");
+ return serialPortInfoList;
+ }
+
+ QAndroidJniEnvironment envL;
+ jobjectArray objArrayL = resultL.object();
+ int countL = envL->GetArrayLength(objArrayL);
+
+ for (int iL=0; iLGetObjectArrayElement(objArrayL, iL));
+ const char *rawStringL = envL->GetStringUTFChars(stringL, 0);
+ __android_log_print(ANDROID_LOG_INFO, V_TAG, "Adding device: %s", rawStringL);
+ QStringList strListL = QString::fromUtf8(rawStringL).split(QStringLiteral(":"));
+ envL->ReleaseStringUTFChars(stringL, rawStringL);
+
+ infoL.d_ptr->portName = strListL[0];
+ infoL.d_ptr->device = strListL[0];
+ infoL.d_ptr->manufacturer = strListL[1];
+ infoL.d_ptr->productIdentifier = strListL[2].toInt();
+ infoL.d_ptr->hasProductIdentifier = (infoL.d_ptr->productIdentifier != 0) ? true: false;
+ infoL.d_ptr->vendorIdentifier = strListL[3].toInt();
+ infoL.d_ptr->hasVendorIdentifier = (infoL.d_ptr->vendorIdentifier != 0) ? true: false;
+
+ serialPortInfoList.append(infoL);
+ }
+
+ return serialPortInfoList;
+}
+
+QList availablePortsBySysfs()
+{
+ return availablePortsByFiltersOfDevices();
+}
+
+QList availablePortsByUdev()
+{
+ return availablePortsByFiltersOfDevices();
+}
+
+QList QSerialPortInfo::availablePorts()
+{
+ return availablePortsByFiltersOfDevices();
+}
+
+QList QSerialPortInfo::standardBaudRates()
+{
+ return QSerialPortPrivate::standardBaudRates();
+}
+
+bool QSerialPortInfo::isBusy() const
+{
+ QAndroidJniObject jstrL = QAndroidJniObject::fromString(d_ptr->portName);
+ jboolean resultL = QAndroidJniObject::callStaticMethod(
+ V_jniClassName,
+ "isDeviceNameOpen",
+ "(Ljava/lang/String;)Z",
+ jstrL.object());
+ return resultL;
+}
+
+bool QSerialPortInfo::isValid() const
+{
+ QAndroidJniObject jstrL = QAndroidJniObject::fromString(d_ptr->portName);
+ jboolean resultL = QAndroidJniObject::callStaticMethod(
+ V_jniClassName,
+ "isDeviceNameValid",
+ "(Ljava/lang/String;)Z",
+ jstrL.object());
+ return resultL;
+}
+
+QString QSerialPortInfoPrivate::portNameToSystemLocation(const QString &source)
+{
+ return (source.startsWith(QLatin1Char('/'))
+ || source.startsWith(QStringLiteral("./"))
+ || source.startsWith(QStringLiteral("../")))
+ ? source : (QStringLiteral("/dev/") + source);
+}
+
+QString QSerialPortInfoPrivate::portNameFromSystemLocation(const QString &source)
+{
+ return source.startsWith(QStringLiteral("/dev/"))
+ ? source.mid(5) : source;
+}
+
+QT_END_NAMESPACE
+
diff --git a/libs/qtandroidserialport/src/qserialportinfo_p.h b/libs/qtandroidserialport/src/qserialportinfo_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9f108638f68f5dd3835e00a031bc9701b9a6bcd
--- /dev/null
+++ b/libs/qtandroidserialport/src/qserialportinfo_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov
+** Copyright (C) 2011 Sergey Belyashov
+** Copyright (C) 2012 Laszlo Papp
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERIALPORTINFO_P_H
+#define QSERIALPORTINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QSerialPortInfoPrivate
+{
+public:
+ QSerialPortInfoPrivate()
+ : vendorIdentifier(0)
+ , productIdentifier(0)
+ , hasVendorIdentifier(false)
+ , hasProductIdentifier(false)
+ {
+ }
+
+ ~QSerialPortInfoPrivate()
+ {
+ }
+
+ static QString portNameToSystemLocation(const QString &source);
+ static QString portNameFromSystemLocation(const QString &source);
+
+ QString portName;
+ QString device;
+ QString description;
+ QString manufacturer;
+ QString serialNumber;
+
+ quint16 vendorIdentifier;
+ quint16 productIdentifier;
+
+ bool hasVendorIdentifier;
+ bool hasProductIdentifier;
+};
+
+class QSerialPortInfoPrivateDeleter
+{
+public:
+ static void cleanup(QSerialPortInfoPrivate *p) {
+ delete p;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSERIALPORTINFO_P_H
diff --git a/libs/qtandroidserialport/src/qtandroidserialport.pri b/libs/qtandroidserialport/src/qtandroidserialport.pri
new file mode 100644
index 0000000000000000000000000000000000000000..9bf07c0ad88a78d7f41b4c8f24171de371f7d7d6
--- /dev/null
+++ b/libs/qtandroidserialport/src/qtandroidserialport.pri
@@ -0,0 +1,28 @@
+android {
+
+ QT += androidextras
+
+ INCLUDEPATH += $$PWD
+
+ PUBLIC_HEADERS += \
+ $$PWD/qserialport.h \
+ $$PWD/qserialportinfo.h
+
+ PRIVATE_HEADERS += \
+ $$PWD/qserialport_p.h \
+ $$PWD/qserialportinfo_p.h \
+ $$PWD/qserialport_android_p.h
+
+ SOURCES += \
+ $$PWD/qserialport.cpp \
+ $$PWD/qserialportinfo.cpp \
+ $$PWD/qserialport_android.cpp \
+ $$PWD/qserialportinfo_android.cpp
+
+ CONFIG += mobility
+
+ INCLUDEPATH += $$PWD/qt4support/include
+
+ HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
+
+}
diff --git a/src/QGC.h b/src/QGC.h
index 2ffca0600b2f428b388703fa77075fbae2d54f86..35f58e14ede8136a4d21ff2edb64c3ca60bfa14e 100644
--- a/src/QGC.h
+++ b/src/QGC.h
@@ -60,6 +60,9 @@ inline bool isinf(T value)
#define isinf(x) std::isinf(x)
#endif
#endif
+#ifdef __android__
+#define isinf(x) std::isinf(x)
+#endif
namespace QGC
{
diff --git a/src/QGCFileDialog.cc b/src/QGCFileDialog.cc
index 25c667ea928685dd4ffa8a46cef47e300d70ab07..b3160b50c59354bddec766c0c736512dc205f626 100644
--- a/src/QGCFileDialog.cc
+++ b/src/QGCFileDialog.cc
@@ -26,8 +26,10 @@
#include
#include "MainWindow.h"
#ifdef QT_DEBUG
+#ifndef __android__
#include "UnitTest.h"
#endif
+#endif
QString QGCFileDialog::getExistingDirectory(
QWidget* parent,
@@ -38,9 +40,11 @@ QString QGCFileDialog::getExistingDirectory(
_validate(options);
#ifdef QT_DEBUG
+#ifndef __android__
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getExistingDirectory(parent, caption, dir, options);
} else
+#endif
#endif
{
return QFileDialog::getExistingDirectory(parent, caption, dir, options);
@@ -57,9 +61,11 @@ QString QGCFileDialog::getOpenFileName(
_validate(options);
#ifdef QT_DEBUG
+#ifndef __android__
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getOpenFileName(parent, caption, dir, filter, options);
} else
+#endif
#endif
{
return QFileDialog::getOpenFileName(parent, caption, dir, filter, NULL, options);
@@ -76,9 +82,11 @@ QStringList QGCFileDialog::getOpenFileNames(
_validate(options);
#ifdef QT_DEBUG
+#ifndef __android__
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getOpenFileNames(parent, caption, dir, filter, options);
} else
+#endif
#endif
{
return QFileDialog::getOpenFileNames(parent, caption, dir, filter, NULL, options);
@@ -97,9 +105,11 @@ QString QGCFileDialog::getSaveFileName(
_validate(options);
#ifdef QT_DEBUG
+#ifndef __android__
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getSaveFileName(parent, caption, dir, filter, defaultSuffix, options);
} else
+#endif
#endif
{
QString defaultSuffixCopy(defaultSuffix);
diff --git a/src/QGCMessageBox.h b/src/QGCMessageBox.h
index dfda32d18a7bac8e3721784d09ee07f9deb60b63..91402a9d033711b930b8230e4cfba2ca4f3459e5 100644
--- a/src/QGCMessageBox.h
+++ b/src/QGCMessageBox.h
@@ -29,8 +29,10 @@
#include "MainWindow.h"
#include "QGCApplication.h"
#ifdef QT_DEBUG
+#ifndef __android__
#include "UnitTest.h"
#endif
+#endif
/// @file
/// @brief Subclass of QMessageBox which re-implements the static public functions. There are two reasons for this:
@@ -104,10 +106,12 @@ private:
}
#ifdef QT_DEBUG
+#ifndef __android__
if (qgcApp()->runningUnitTests()) {
qDebug() << "QGCMessageBox (unit testing)" << title << text;
return UnitTest::_messageBox(icon, title, text, buttons, defaultButton);
} else
+#endif
#endif
{
#ifdef Q_OS_MAC
diff --git a/src/VehicleSetup/PX4Bootloader.cc b/src/VehicleSetup/PX4Bootloader.cc
index deab12ea492b22da07ec10be313e206825f72268..d5cd1346b885bf79ce4b9461b55313e1640908b9 100644
--- a/src/VehicleSetup/PX4Bootloader.cc
+++ b/src/VehicleSetup/PX4Bootloader.cc
@@ -28,7 +28,11 @@
#include "PX4Bootloader.h"
#include
+#ifdef __android__
+#include "qserialportinfo.h"
+#else
#include
+#endif
#include
#include
diff --git a/src/VehicleSetup/PX4FirmwareUpgradeThread.cc b/src/VehicleSetup/PX4FirmwareUpgradeThread.cc
index 784948eb239a612e1abb0d6c266519242357bf57..0f581facf9834551e9778c1aa5b025fc3558cac8 100644
--- a/src/VehicleSetup/PX4FirmwareUpgradeThread.cc
+++ b/src/VehicleSetup/PX4FirmwareUpgradeThread.cc
@@ -29,7 +29,11 @@
#include "PX4Bootloader.h"
#include
+#ifdef __android__
+#include "qserialportinfo.h"
+#else
#include
+#endif
#include
PX4FirmwareUpgradeThreadWorker::PX4FirmwareUpgradeThreadWorker(QObject* parent) :
diff --git a/src/comm/LinkConfiguration.cc b/src/comm/LinkConfiguration.cc
index b3a351d456346fa4aedf84014976a5f2b36cc701..5e974f30af0602e66240e3ce6fd265b30c9f65ca 100644
--- a/src/comm/LinkConfiguration.cc
+++ b/src/comm/LinkConfiguration.cc
@@ -33,8 +33,10 @@ This file is part of the QGROUNDCONTROL project
#include "TCPLink.h"
#ifdef UNITTEST_BUILD
+#ifndef __android__
#include "MockLink.h"
#endif
+#endif
#define LINK_SETTING_ROOT "LinkConfigurations"
@@ -92,9 +94,11 @@ LinkConfiguration* LinkConfiguration::createSettings(int type, const QString& na
config = new TCPConfiguration(name);
break;
#ifdef UNITTEST_BUILD
+#ifndef __android__
case LinkConfiguration::TypeMock:
config = new MockConfiguration(name);
break;
+#endif
#endif
}
return config;
@@ -118,9 +122,11 @@ LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* sourc
dupe = new TCPConfiguration(dynamic_cast(source));
break;
#ifdef UNITTEST_BUILD
+#ifndef __android__
case TypeMock:
dupe = new MockConfiguration(dynamic_cast(source));
break;
+#endif
#endif
}
return dupe;
diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc
index 91e63ed5c20ee97ad6ffeb7360db866f2b2cd3d9..10b5af4e48099ce518e8d306c88925f47b41dad0 100644
--- a/src/comm/LinkManager.cc
+++ b/src/comm/LinkManager.cc
@@ -32,7 +32,11 @@ This file is part of the QGROUNDCONTROL project
#include
#include
#include
+#ifdef __android__
+#include "qserialportinfo.h"
+#else
#include
+#endif
#include "LinkManager.h"
#include "MainWindow.h"
@@ -85,9 +89,11 @@ LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config)
pLink = new TCPLink(dynamic_cast(config));
break;
#ifdef UNITTEST_BUILD
+#ifndef __android__
case LinkConfiguration::TypeMock:
pLink = new MockLink(dynamic_cast(config));
break;
+#endif
#endif
}
if(pLink) {
@@ -379,10 +385,12 @@ void LinkManager::loadLinkConfigurationList()
pLink->setPreferred(preferred);
break;
#ifdef UNITTEST_BUILD
+#ifndef __android__
case LinkConfiguration::TypeMock:
pLink = (LinkConfiguration*)new MockConfiguration(name);
pLink->setPreferred(false);
break;
+#endif
#endif
}
if(pLink) {
diff --git a/src/comm/LinkManager.h b/src/comm/LinkManager.h
index 0fba35a4ab63882564d84e586016743776aaa387..3fdca2ab4ff0247fb944fc1f1746ef74a4baef3e 100644
--- a/src/comm/LinkManager.h
+++ b/src/comm/LinkManager.h
@@ -40,8 +40,10 @@ This file is part of the PIXHAWK project
#include "TCPLink.h"
#ifdef UNITTEST_BUILD
+#ifndef __android__
#include "MockLink.h"
#endif
+#endif
#include "ProtocolInterface.h"
#include "QGCSingleton.h"
diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc
index 415b77c6fee779d8023340d70baede7f817d1c7d..9cd1f2b3fbb0d6995244822a9a47e70384456f5c 100644
--- a/src/comm/SerialLink.cc
+++ b/src/comm/SerialLink.cc
@@ -12,8 +12,14 @@
#include
#include
#include
+
+#ifdef __android__
+#include "qserialport.h"
+#include "qserialportinfo.h"
+#else
#include
#include
+#endif
#include "SerialLink.h"
#include "QGC.h"
diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h
index 29bdb6a69aa69ce712a048201bf1433c7228ed51..8f2011e83b84e2bf42f738be511c5ff68274873f 100644
--- a/src/comm/SerialLink.h
+++ b/src/comm/SerialLink.h
@@ -40,7 +40,11 @@ class SerialLink;
#include
#include
#include
+#ifdef __android__
+#include "qserialport.h"
+#else
#include
+#endif
#include
#include
diff --git a/src/main.cc b/src/main.cc
index 0f1615dec9eeea202e1c3e826c96cb888c2659ec..5f6dc5f28707f8de438222e23c660205e7a34680 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -35,7 +35,9 @@ This file is part of the QGROUNDCONTROL project
#include "MainWindow.h"
#include "configuration.h"
#ifdef QT_DEBUG
+#ifndef __android__
#include "UnitTest.h"
+#endif
#include "CmdLineOptParser.h"
#ifdef Q_OS_WIN
#include
@@ -156,6 +158,7 @@ int main(int argc, char *argv[])
int exitCode;
+#ifndef __android__
#ifdef QT_DEBUG
if (runUnitTests) {
if (!app->_initForUnitTests()) {
@@ -171,6 +174,7 @@ int main(int argc, char *argv[])
}
exitCode = -failures;
} else
+#endif
#endif
{
if (!app->_initForNormalAppBoot()) {
diff --git a/src/qgcunittest/UnitTest.h b/src/qgcunittest/UnitTest.h
index bbc78acb191500f23203e74edba0fb0f7569e2a1..5e46eff7fdbe777bef4809c97e7332506e6fa582 100644
--- a/src/qgcunittest/UnitTest.h
+++ b/src/qgcunittest/UnitTest.h
@@ -28,6 +28,7 @@
#ifndef UNITTEST_H
#define UNITTEST_H
+#ifndef __android__
#include
#include
@@ -186,4 +187,5 @@ private:
QSharedPointer _unitTest;
};
+#endif // Android
#endif
diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc
index 144a4f0ebf6a8a45d2c909ced9f2f8b73c191d91..8d20f4ea787267c36ae8c8e1e684c80c12e612f4 100644
--- a/src/ui/MainWindow.cc
+++ b/src/ui/MainWindow.cc
@@ -45,7 +45,9 @@ This file is part of the QGROUNDCONTROL project
#include "MAVLinkProtocol.h"
#include "QGCWaypointListMulti.h"
#include "MainWindow.h"
+#ifndef __android__
#include "JoystickWidget.h"
+#endif
#include "GAudioOutput.h"
#include "QGCToolWidget.h"
#include "QGCMAVLinkLogPlayer.h"
@@ -193,8 +195,9 @@ MainWindow::MainWindow(QSplashScreen* splashScreen)
connectCommonActions();
// Connect user interface devices
emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
+#ifndef __android__
joystick = new JoystickInput();
-
+#endif
#ifdef QGC_MOUSE_ENABLED_WIN
emit initStatusChanged(tr("Initializing 3D mouse interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
mouseInput = new Mouse3DInput(this);
@@ -315,6 +318,7 @@ MainWindow::~MainWindow()
delete _simulationLink;
_simulationLink = NULL;
}
+#ifndef __android__
if (joystick)
{
joystick->shutdown();
@@ -322,6 +326,7 @@ MainWindow::~MainWindow()
delete joystick;
joystick = NULL;
}
+#endif
// Delete all UAS objects
for (int i=0;i<_commsWidgetList.size();i++)
{
@@ -945,7 +950,11 @@ void MainWindow::showRoadMap()
void MainWindow::showSettings()
{
+#ifndef __android__
SettingsDialog settings(joystick, this);
+#else
+ SettingsDialog settings(this);
+#endif
settings.exec();
}
@@ -1268,7 +1277,11 @@ void MainWindow::hideSplashScreen(void)
void MainWindow::manageLinks()
{
+#ifndef __android__
SettingsDialog settings(joystick, this, SettingsDialog::ShowCommLinks);
+#else
+ SettingsDialog settings(this, SettingsDialog::ShowCommLinks);
+#endif
settings.exec();
}
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index 95d78384cc24c3eefa697e132b8cbab483e8bf79..03963e500d120ae19fbff343381474450c6c577d 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -48,7 +48,9 @@ This file is part of the QGROUNDCONTROL project
#include "CameraView.h"
#include "UASListWidget.h"
#include "MAVLinkSimulationLink.h"
+#ifndef __android__
#include "input/JoystickInput.h"
+#endif
#if (defined QGC_MOUSE_ENABLED_WIN) | (defined QGC_MOUSE_ENABLED_LINUX)
#include "Mouse6dofInput.h"
#endif // QGC_MOUSE_ENABLED_WIN
@@ -252,7 +254,9 @@ protected:
QPointer fileWidget;
+#ifndef __android__
JoystickInput* joystick; ///< The joystick manager for QGC
+#endif
#ifdef QGC_MOUSE_ENABLED_WIN
/** @brief 3d Mouse support (WIN only) */
diff --git a/src/ui/SerialConfigurationWindow.cc b/src/ui/SerialConfigurationWindow.cc
index 4b04dc9a207aa83f5320bb3f33c3e380e6d1bac0..7f9e21cd7f7e44d24e8f6ad16f402180b93fa269 100644
--- a/src/ui/SerialConfigurationWindow.cc
+++ b/src/ui/SerialConfigurationWindow.cc
@@ -32,7 +32,12 @@ This file is part of the QGROUNDCONTROL project
#include
#include
#include
+
+#ifdef __android__
+#include "qserialportinfo.h"
+#else
#include
+#endif
#include
#include
diff --git a/src/ui/SettingsDialog.cc b/src/ui/SettingsDialog.cc
index d8561886557ed08f743df99cb6e4a4e66ab56039..56e3fcfb51ff48a45f09b6e37f8ea7ce87d8873f 100644
--- a/src/ui/SettingsDialog.cc
+++ b/src/ui/SettingsDialog.cc
@@ -28,7 +28,9 @@
#include "MainWindow.h"
#include "ui_SettingsDialog.h"
+#ifndef __android__
#include "JoystickWidget.h"
+#endif
#include "LinkManager.h"
#include "MAVLinkProtocol.h"
#include "MAVLinkSettingsWidget.h"
@@ -39,7 +41,11 @@
#include "QGCMessageBox.h"
#include "MainToolBar.h"
+#ifndef __android__
SettingsDialog::SettingsDialog(JoystickInput *joystick, QWidget *parent, int showTab, Qt::WindowFlags flags) :
+#else
+SettingsDialog::SettingsDialog(QWidget *parent, int showTab, Qt::WindowFlags flags) :
+#endif
QDialog(parent, flags),
_mainWindow(MainWindow::instance()),
_ui(new Ui::SettingsDialog)
@@ -52,13 +58,17 @@ _ui(new Ui::SettingsDialog)
move(position.topLeft());
QGCLinkConfiguration* pLinkConf = new QGCLinkConfiguration(this);
+#ifndef __android__
JoystickWidget* pJoystickConf = new JoystickWidget(joystick, this);
+#endif
MAVLinkSettingsWidget* pMavsettings = new MAVLinkSettingsWidget(MAVLinkProtocol::instance(), this);
// Add the link settings pane
_ui->tabWidget->addTab(pLinkConf, "Comm Links");
+#ifndef __android__
// Add the joystick settings pane
_ui->tabWidget->addTab(pJoystickConf, "Controllers");
+#endif
// Add the MAVLink settings pane
_ui->tabWidget->addTab(pMavsettings, "MAVLink");
@@ -102,9 +112,11 @@ _ui(new Ui::SettingsDialog)
case ShowCommLinks:
_ui->tabWidget->setCurrentWidget(pLinkConf);
break;
+#ifndef __android__
case ShowControllers:
_ui->tabWidget->setCurrentWidget(pJoystickConf);
break;
+#endif
case ShowMavlink:
_ui->tabWidget->setCurrentWidget(pMavsettings);
break;
diff --git a/src/ui/SettingsDialog.h b/src/ui/SettingsDialog.h
index b8a3f8bedd287e7f0486b5f58b79844b41d5e868..e06128847169c839be9bb8e49672bd574d83956a 100644
--- a/src/ui/SettingsDialog.h
+++ b/src/ui/SettingsDialog.h
@@ -45,7 +45,11 @@ public:
ShowMavlink
};
+#ifdef __android__
+ SettingsDialog(QWidget *parent = 0, int showTab = ShowDefault, Qt::WindowFlags flags = Qt::Sheet);
+#else
SettingsDialog(JoystickInput *joystick, QWidget *parent = 0, int showTab = ShowDefault, Qt::WindowFlags flags = Qt::Sheet);
+#endif
~SettingsDialog();
public slots:
diff --git a/src/ui/configuration/SerialSettingsDialog.cc b/src/ui/configuration/SerialSettingsDialog.cc
index 83418c9d992ccd9d535a94941590dbf3a6489646..2b5c6b4792174cc2365cd21a3e1dcdcb45bd7d72 100644
--- a/src/ui/configuration/SerialSettingsDialog.cc
+++ b/src/ui/configuration/SerialSettingsDialog.cc
@@ -37,8 +37,13 @@ This file is part of the APM_PLANNER project
#include "terminalconsole.h"
#include "ui_SerialSettingsDialog.h"
+#ifdef __android__
+#include "qserialport.h"
+#include "qserialportinfo.h"
+#else
#include
#include
+#endif
#include
#include
diff --git a/src/ui/configuration/SerialSettingsDialog.h b/src/ui/configuration/SerialSettingsDialog.h
index 79eff0e72c70f247c033a1a84c18da83a7b4648b..3aec3deca971943a2b4a51347863e2eb2e793544 100644
--- a/src/ui/configuration/SerialSettingsDialog.h
+++ b/src/ui/configuration/SerialSettingsDialog.h
@@ -37,7 +37,11 @@ This file is part of the APM_PLANNER project
#define SERIALSETTINGSDIALOG_H
#include
+#ifdef __android__
+#include "qserialport.h"
+#else
#include
+#endif
namespace Ui {
class SerialSettingsDialog;
diff --git a/src/ui/configuration/terminalconsole.cpp b/src/ui/configuration/terminalconsole.cpp
index 54a090f51620cbd48c1a89577dcd48a510a5e66a..fe1a0d7fc89740446abd2a70f3a92dd682d1f579 100644
--- a/src/ui/configuration/terminalconsole.cpp
+++ b/src/ui/configuration/terminalconsole.cpp
@@ -45,8 +45,13 @@ This file is part of the APM_PLANNER project
#include
#include
#include
+#ifdef __android__
+#include "qserialport.h"
+#include "qserialportinfo.h"
+#else
#include
#include
+#endif
TerminalConsole::TerminalConsole(QWidget *parent) :
QWidget(parent),
diff --git a/src/ui/configuration/terminalconsole.h b/src/ui/configuration/terminalconsole.h
index f100a6ef24e83fdeed46bc8100af3f5daf65f6eb..909416edd95a613842fcc7318617347125b2aa20 100644
--- a/src/ui/configuration/terminalconsole.h
+++ b/src/ui/configuration/terminalconsole.h
@@ -39,7 +39,11 @@ This file is part of the APM_PLANNER project
#include "SerialSettingsDialog.h"
#include
+#ifdef __android__
+#include "qserialport.h"
+#else
#include
+#endif
namespace Ui {
class TerminalConsole;
diff --git a/src/ui/designer/QGCParamSlider.h b/src/ui/designer/QGCParamSlider.h
index 9ca92423bfa616b9821f00f041704e31b5499d1d..ab3048dbb05a6def730af20539b0d70fd0664cbb 100644
--- a/src/ui/designer/QGCParamSlider.h
+++ b/src/ui/designer/QGCParamSlider.h
@@ -3,7 +3,9 @@
#include
#include
+#ifndef __android__
#include
+#endif
#include "QGCToolWidgetItem.h"
diff --git a/src/ui/designer/QGCToolWidgetComboBox.h b/src/ui/designer/QGCToolWidgetComboBox.h
index 785d606a4ec7a860097a1a51c154d8ee026d2e5a..9b4d162f4c43b5b55fac050efb37c3a4da6ea4aa 100644
--- a/src/ui/designer/QGCToolWidgetComboBox.h
+++ b/src/ui/designer/QGCToolWidgetComboBox.h
@@ -3,8 +3,9 @@
#include
#include
+#ifndef __android__
#include
-
+#endif
#include "QGCToolWidgetItem.h"
class QGCUASParamManagerInterface;
diff --git a/src/ui/toolbar/MainToolBar.cc b/src/ui/toolbar/MainToolBar.cc
index 560c664e9ad3a356ad6e45febccddbe04a4b086a..876214ac7184372a7f343344ceeb748216a227ec 100644
--- a/src/ui/toolbar/MainToolBar.cc
+++ b/src/ui/toolbar/MainToolBar.cc
@@ -64,8 +64,13 @@ MainToolBar::MainToolBar(QWidget* parent)
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
setObjectName("MainToolBar");
+#ifdef __android__
+ setMinimumHeight(120);
+ setMaximumHeight(120);
+#else
setMinimumHeight(40);
setMaximumHeight(40);
+#endif
setMinimumWidth(MainWindow::instance()->minimumWidth());
// Get rid of layout default margins
QLayout* pl = layout();
diff --git a/src/ui/toolbar/MainToolBar.qml b/src/ui/toolbar/MainToolBar.qml
index efed1d7f74dac39c0b5de8e73180bd867f534206..f5890994738c834bfb95cf981f612ea98604b3c8 100644
--- a/src/ui/toolbar/MainToolBar.qml
+++ b/src/ui/toolbar/MainToolBar.qml
@@ -38,13 +38,14 @@ import QGroundControl.MainToolBar 1.0
import QGroundControl.ScreenTools 1.0
Rectangle {
+ id: toolBarHolder
property var qgcPal: QGCPalette { id: palette; colorGroupEnabled: true }
property ScreenTools screenTools: ScreenTools { }
- property int cellSpacerSize: 4
- property int cellHeight: 30
- property int cellRadius: 3
+ property int cellSpacerSize: getProportionalDimmension(4)
+ property int cellHeight: getProportionalDimmension(30)
+ property int cellRadius: getProportionalDimmension(3)
property var colorBlue: "#1a6eaa"
property var colorGreen: "#079527"
@@ -57,9 +58,16 @@ Rectangle {
property var colorGreenText: (qgcPal.globalTheme === QGCPalette.Light) ? "#046b1b" : "#00d930"
property var colorWhiteText: (qgcPal.globalTheme === QGCPalette.Light) ? "#343333" : "#f0f0f0"
- id: toolBarHolder
color: qgcPal.windowShade
+ Component.onCompleted: {
+ console.log(cellSpacerSize, cellHeight, cellRadius);
+ }
+
+ function getProportionalDimmension(val) {
+ return toolBarHolder.height * val / 40
+ }
+
function getMessageColor() {
if(mainToolBar.messageType === MainToolBar.MessageNone)
return qgcPal.button;
@@ -126,14 +134,14 @@ Rectangle {
id: row1
height: cellHeight
anchors.left: parent.left
- spacing: 4
+ spacing: getProportionalDimmension(4)
anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: 10
+ anchors.leftMargin: getProportionalDimmension(10)
Row {
id: row11
height: cellHeight
- spacing: -12
+ spacing: -getProportionalDimmension(12)
anchors.verticalCenter: parent.verticalCenter
Connections {
target: screenTools
@@ -149,7 +157,7 @@ Rectangle {
QGCToolBarButton {
id: setupButton
- width: 90
+ width: getProportionalDimmension(90)
height: cellHeight
exclusiveGroup: mainActionGroup
text: qsTr("Setup")
@@ -163,7 +171,7 @@ Rectangle {
QGCToolBarButton {
id: planButton
- width: 90
+ width: getProportionalDimmension(90)
height: cellHeight
exclusiveGroup: mainActionGroup
text: qsTr("Plan")
@@ -177,7 +185,7 @@ Rectangle {
QGCToolBarButton {
id: flyButton
- width: 90
+ width: getProportionalDimmension(90)
height: cellHeight
exclusiveGroup: mainActionGroup
text: qsTr("Fly")
@@ -191,7 +199,7 @@ Rectangle {
QGCToolBarButton {
id: analyzeButton
- width: 90
+ width: getProportionalDimmension(90)
height: cellHeight
exclusiveGroup: mainActionGroup
text: qsTr("Analyze")
@@ -213,7 +221,7 @@ Rectangle {
Rectangle {
id: messages
- width: (mainToolBar.messageCount > 99) ? 70 : 60
+ width: (mainToolBar.messageCount > 99) ? getProportionalDimmension(70) : getProportionalDimmension(60)
height: cellHeight
visible: (mainToolBar.connectionCount > 0) && (mainToolBar.showMessages)
anchors.verticalCenter: parent.verticalCenter
@@ -226,11 +234,11 @@ Rectangle {
Image {
id: messageIcon
source: getMessageIcon();
- height: 16
+ height: getProportionalDimmension(16)
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
- anchors.leftMargin: 10
+ anchors.leftMargin: getProportionalDimmension(10)
}
Rectangle {
@@ -256,8 +264,8 @@ Rectangle {
visible: (messages.showTriangle) && (mainToolBar.messageCount > 0)
anchors.bottom: parent.bottom
anchors.right: parent.right
- anchors.bottomMargin: 3
- anchors.rightMargin: 3
+ anchors.bottomMargin: getProportionalDimmension(3)
+ anchors.rightMargin: getProportionalDimmension(3)
}
Timer {
@@ -306,7 +314,7 @@ Rectangle {
Rectangle {
id: satelitte
- width: 60
+ width: getProportionalDimmension(60)
height: cellHeight
visible: showMavStatus() && (mainToolBar.showGPS)
anchors.verticalCenter: parent.verticalCenter
@@ -317,11 +325,11 @@ Rectangle {
Image {
source: "qrc:/res/Gps";
- height: 24
+ height: getProportionalDimmension(24)
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
- anchors.leftMargin: 10
+ anchors.leftMargin: getProportionalDimmension(10)
mipmap: true
smooth: true
}
@@ -333,7 +341,7 @@ Rectangle {
font.weight: Font.DemiBold
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
- anchors.rightMargin: 10
+ anchors.rightMargin: getProportionalDimmension(10)
horizontalAlignment: Text.AlignRight
color: colorWhite
}
@@ -341,7 +349,7 @@ Rectangle {
Rectangle {
id: battery
- width: 80
+ width: getProportionalDimmension(80)
height: cellHeight
visible: showMavStatus() && (mainToolBar.showBattery)
anchors.verticalCenter: parent.verticalCenter
@@ -352,11 +360,11 @@ Rectangle {
Image {
source: getBatteryIcon();
- height: 20
+ height: getProportionalDimmension(20)
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
- anchors.leftMargin: 6
+ anchors.leftMargin: getProportionalDimmension(6)
mipmap: true
smooth: true
}
@@ -368,7 +376,7 @@ Rectangle {
font.weight: Font.DemiBold
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
- anchors.rightMargin: 8
+ anchors.rightMargin: getProportionalDimmension(8)
horizontalAlignment: Text.AlignRight
color: colorWhite
}
@@ -377,7 +385,7 @@ Rectangle {
Column {
visible: showMavStatus()
height: cellHeight * 0.85
- width: 80
+ width: getProportionalDimmension(80)
anchors.verticalCenter: parent.verticalCenter
Rectangle {
@@ -422,7 +430,7 @@ Rectangle {
Rectangle {
id: modeStatus
- width: 90
+ width: getProportionalDimmension(90)
height: cellHeight
visible: showMavStatus()
color: "#00000000"
@@ -442,7 +450,7 @@ Rectangle {
Rectangle {
id: connectionStatus
- width: 160
+ width: getProportionalDimmension(160)
height: cellHeight
visible: (mainToolBar.connectionCount > 0 && mainToolBar.mavPresent && mainToolBar.heartbeatTimeout != 0)
anchors.verticalCenter: parent.verticalCenter
@@ -469,8 +477,8 @@ Rectangle {
spacing: cellSpacerSize
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: 10
- anchors.rightMargin: 10
+ anchors.leftMargin: getProportionalDimmension(10)
+ anchors.rightMargin: getProportionalDimmension(10)
Menu {
id: connectMenu
@@ -501,7 +509,7 @@ Rectangle {
QGCButton {
id: connectButton
- width: 100
+ width: getProportionalDimmension(100)
visible: mainToolBar.connectionCount === 0
text: qsTr("Connect")
menu: connectMenu
@@ -510,7 +518,7 @@ Rectangle {
QGCButton {
id: disconnectButton
- width: 100
+ width: getProportionalDimmension(100)
visible: mainToolBar.connectionCount === 1
text: qsTr("Disconnect")
anchors.verticalCenter: parent.verticalCenter
@@ -539,7 +547,7 @@ Rectangle {
QGCButton {
id: multidisconnectButton
- width: 100
+ width: getProportionalDimmension(100)
text: "Disconnect"
visible: mainToolBar.connectionCount > 1
menu: disconnectMenu
@@ -550,8 +558,7 @@ Rectangle {
// Progress bar
Rectangle {
- readonly property int progressBarHeight: 3
-
+ readonly property int progressBarHeight: getProportionalDimmension(3)
y: parent.height - progressBarHeight
height: progressBarHeight
width: parent.width * mainToolBar.progressBarValue