Commit 59ad9be7 authored by dogmaphobic's avatar dogmaphobic

First android commit.

parent 9a141821
......@@ -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
}
......@@ -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")
}
......
......@@ -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
}
}
#
......
<?xml version="1.0"?>
<manifest package="org.qgroundcontrol" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.3.0" android:versionCode="2" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:icon="@drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qgroundcontrol.qgchelper.UsbDeviceJNI" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="reverseLandscape" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/>
</intent-filter>
<!-- Needed to keep working while 'asleep' -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- Support devices without USB host mode since there are other connection types -->
<uses-feature android:name="android.hardware.usb.host" android:required="false"/>
<meta-data android:resource="@xml/device_filter" android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
<meta-data android:resource="@xml/device_filter" android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/>
<!-- Rest of Standard Manifest -->
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Splash screen -->
<!--
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
-->
<!-- Splash screen -->
<!-- Background running -->
<!-- Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after
"applicationStateChanged(Qt::ApplicationSuspended)"
signal is sent! -->
<meta-data android:name="android.app.background_running" android:value="false"/>
<!-- Background running -->
</activity>
</application>
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Everything -->
<usb-device />
<!-- 0x26AC / 0x11: PX4 FMU Pixhawk -->
<!--
<usb-device vendor-id="9900" product-id="17" />
-->
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
<!--
<usb-device vendor-id="1027" product-id="24577" />
-->
<!-- 0x0403 / 0x6015: FTDI FT231X -->
<!--
<usb-device vendor-id="1027" product-id="24597" />
-->
<!-- 0x2341 / Arduino -->
<!--
<usb-device vendor-id="9025" />
-->
<!-- 0x16C0 / 0x0483: Teensyduino -->
<!--
<usb-device vendor-id="5824" product-id="1155" />
-->
<!-- 0x10C4 / 0xEA60: CP210x UART Bridge -->
<!--
<usb-device vendor-id="4292" product-id="60000" />
-->
<!-- 0x067B / 0x2303: Prolific PL2303 -->
<!--
<usb-device vendor-id="1659" product-id="8963" />
-->
</resources>
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* USB CDC/ACM serial driver implementation.
*
* @author mike wakerly (opensource@hoho.com)
* @see <a
* href="http://www.usb.org/developers/devclass_docs/usbcdc11.pdf">Universal
* Serial Bus Class Definitions for Communication Devices, v1.1</a>
*/
public class CdcAcmSerialDriver extends CommonUsbSerialDriver {
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
private UsbInterface mControlInterface;
private UsbInterface mDataInterface;
private UsbEndpoint mControlEndpoint;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private boolean mRts = false;
private boolean mDtr = false;
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
private static final int GET_LINE_CODING = 0x21;
private static final int SET_CONTROL_LINE_STATE = 0x22;
private static final int SEND_BREAK = 0x23;
public CdcAcmSerialDriver(UsbDevice device, 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<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),
new int[] {
UsbId.ARDUINO_UNO,
UsbId.ARDUINO_UNO_R3,
UsbId.ARDUINO_MEGA_2560,
UsbId.ARDUINO_MEGA_2560_R3,
UsbId.ARDUINO_SERIAL_ADAPTER,
UsbId.ARDUINO_SERIAL_ADAPTER_R3,
UsbId.ARDUINO_MEGA_ADK,
UsbId.ARDUINO_MEGA_ADK_R3,
UsbId.ARDUINO_LEONARDO,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),
new int[] {
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL),
new int[] {
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS),
new int[] {
UsbId.LEAFLABS_MAPLE,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PX4),
new int[] {
UsbId.DEVICE_PX4FMU,
});
return supportedDevices;
}
}
/* 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;
}
}
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<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILAB),
new int[] {
UsbId.SILAB_CP2102
});
return supportedDevices;
}
}
/* 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
* <p>
* This driver is based on
* <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>, and is
* copyright and subject to the following terms:
*
* <pre>
* Copyright (C) 2003 by Intra2net AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation;
*
* opensource@intra2net.com
* http://www.intra2net.com/en/developer/libftdi
* </pre>
*
* </p>
* <p>
* Some FTDI devices have not been tested; see later listing of supported and
* unsupported devices. Devices listed as "supported" support the following
* features:
* <ul>
* <li>Read and write of serial data (see {@link #read(byte[], int)} and
* {@link #write(byte[], int)}.
* <li>Setting baud rate (see {@link #setBaudRate(int)}).
* </ul>
* </p>
* <p>
* Supported and tested devices:
* <ul>
* <li>{@value DeviceType#TYPE_R}</li>
* </ul>
* </p>
* <p>
* Unsupported but possibly working devices (please contact the author with
* feedback or patches):
* <ul>
* <li>{@value DeviceType#TYPE_2232C}</li>
* <li>{@value DeviceType#TYPE_2232H}</li>
* <li>{@value DeviceType#TYPE_4232H}</li>
* <li>{@value DeviceType#TYPE_AM}</li>
* <li>{@value DeviceType#TYPE_BM}</li>
* </ul>
* </p>
*
* @author mike wakerly (opensource@hoho.com)
* @see <a href="http://code.google.com/p/usb-serial-for-android/">USB Serial
* for Android project page</a>
* @see <a href="http://www.ftdichip.com/">FTDI Homepage</a>
* @see <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>
*/
public class FtdiSerialDriver extends CommonUsbSerialDriver {
public static final int USB_TYPE_STANDARD = 0x00 << 5;
public static final int USB_TYPE_CLASS = 0x00 << 5;
public static final int USB_TYPE_VENDOR = 0x00 << 5;
public static final int USB_TYPE_RESERVED = 0x00 << 5;
public static final int USB_RECIP_DEVICE = 0x00;
public static final int USB_RECIP_INTERFACE = 0x01;
public static final int USB_RECIP_ENDPOINT = 0x02;
public static final int USB_RECIP_OTHER = 0x03;
public static final int USB_ENDPOINT_IN = 0x80;
public static final int USB_ENDPOINT_OUT = 0x00;
public static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
public static final int USB_READ_TIMEOUT_MILLIS = 5000;
// From ftdi.h
/**
* Reset the port.
*/
private static final int SIO_RESET_REQUEST = 0;
/**
* Set the modem control register.
*/
private static final int SIO_MODEM_CTRL_REQUEST = 1;
/**
* Set flow control register.
*/
private static final int SIO_SET_FLOW_CTRL_REQUEST = 2;
/**
* Set baud rate.
*/
private static final int SIO_SET_BAUD_RATE_REQUEST = 3;
/**
* Set the data characteristics of the port.
*/
private static final int SIO_SET_DATA_REQUEST = 4;
private static final int SIO_RESET_SIO = 0;
private static final int SIO_RESET_PURGE_RX = 1;
private static final int SIO_RESET_PURGE_TX = 2;
public static final int FTDI_DEVICE_OUT_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT;
public static final int FTDI_DEVICE_IN_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;
/**
* Length of the modem status header, transmitted with every read.
*/
private static final int MODEM_STATUS_HEADER_LENGTH = 2;
private final String TAG = FtdiSerialDriver.class.getSimpleName();
private DeviceType mType;
/**
* FTDI chip types.
*/
private static enum DeviceType {
TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H;
}
private int mInterface = 0; /* INTERFACE_ANY */
private int mMaxPacketSize = 64; // TODO(mikey): detect
/**
* Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
* since it gives no indication of number of bytes read. Set this to
* {@code true} on platforms where it is fixed.
*/
private static final boolean ENABLE_ASYNC_READS = false;
/**
* 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<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
new int[] {
UsbId.FTDI_FT232R,
UsbId.FTDI_FT231X,
});
/*
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PX4),
new int[] {
UsbId.DEVICE_PX4FMU
});
*/
return supportedDevices;
}
}
/* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
/*
* Ported to usb-serial-for-android
* by Felix Hädicke <felixhaedicke@web.de>
*
* Based on the pyprolific driver written
* by Emmanuel Blot <emmanuel.blot@free.fr>
* See https://github.com/eblot/pyftdi
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
public class ProlificSerialDriver extends CommonUsbSerialDriver {
private static final int USB_READ_TIMEOUT_MILLIS = 1000;
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01;
private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01;
private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
| UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN
| UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
| UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int WRITE_ENDPOINT = 0x02;
private static final int READ_ENDPOINT = 0x83;
private static final int INTERRUPT_ENDPOINT = 0x81;
private static final int FLUSH_RX_REQUEST = 0x08;
private static final int FLUSH_TX_REQUEST = 0x09;
private static final int SET_LINE_REQUEST = 0x20;
private static final int SET_CONTROL_REQUEST = 0x22;
private static final int CONTROL_DTR = 0x01;
private static final int CONTROL_RTS = 0x02;
private static final int STATUS_FLAG_CD = 0x01;
private static final int STATUS_FLAG_DSR = 0x02;
private static final int STATUS_FLAG_RI = 0x08;
private static final int STATUS_FLAG_CTS = 0x80;
private static final int STATUS_BUFFER_SIZE = 10;
private static final int STATUS_BYTE_IDX = 8;
private static final int DEVICE_TYPE_HX = 0;
private static final int DEVICE_TYPE_0 = 1;
private static final int DEVICE_TYPE_1 = 2;
private int mDeviceType = DEVICE_TYPE_HX;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private UsbEndpoint mInterruptEndpoint;
private int mControlLinesValue = 0;
private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1;
private int mStatus = 0;
private volatile Thread mReadStatusThread = null;
private final Object mReadStatusThreadLock = new Object();
boolean mStopReadStatusThread = false;
private IOException mReadStatusException = null;
private final String TAG = ProlificSerialDriver.class.getSimpleName();
private final byte[] inControlTransfer(int requestType, int request,
int value, int index, int length) throws IOException {
byte[] buffer = new byte[length];
int result = mConnection.controlTransfer(requestType, request, value,
index, buffer, length, USB_READ_TIMEOUT_MILLIS);
if (result != length) {
throw new IOException(
String.format("ControlTransfer with value 0x%x failed: %d",
value, result));
}
return buffer;
}
private final void outControlTransfer(int requestType, int request,
int value, int index, byte[] data) throws IOException {
int length = (data == null) ? 0 : data.length;
int result = mConnection.controlTransfer(requestType, request, value,
index, data, length, USB_WRITE_TIMEOUT_MILLIS);
if (result != length) {
throw new IOException(
String.format("ControlTransfer with value 0x%x failed: %d",
value, result));
}
}
private final byte[] vendorIn(int value, int index, int length)
throws IOException {
return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE,
PROLIFIC_VENDOR_READ_REQUEST, value, index, length);
}
private final void vendorOut(int value, int index, byte[] data)
throws IOException {
outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE,
PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data);
}
private final void ctrlOut(int request, int value, int index, byte[] data)
throws IOException {
outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index,
data);
}
private void doBlackMagic() throws IOException {
vendorIn(0x8484, 0, 1);
vendorOut(0x0404, 0, null);
vendorIn(0x8484, 0, 1);
vendorIn(0x8383, 0, 1);
vendorIn(0x8484, 0, 1);
vendorOut(0x0404, 1, null);
vendorIn(0x8484, 0, 1);
vendorIn(0x8383, 0, 1);
vendorOut(0, 1, null);
vendorOut(1, 0, null);
vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null);
}
private void resetDevice() throws IOException {
purgeHwBuffers(true, true);
}
private void setControlLines(int newControlLinesValue) throws IOException {
ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null);
mControlLinesValue = newControlLinesValue;
}
private final void readStatusThreadFunction() {
try {
while (!mStopReadStatusThread) {
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint,
buffer,
STATUS_BUFFER_SIZE,
500);
if (readBytesCount > 0) {
if (readBytesCount == STATUS_BUFFER_SIZE) {
mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
} else {
throw new IOException(
String.format("Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d",
STATUS_BUFFER_SIZE,
readBytesCount));
}
}
}
} catch (IOException e) {
mReadStatusException = e;
}
}
private final int getStatus() throws IOException {
if ((mReadStatusThread == null) && (mReadStatusException == null)) {
synchronized (mReadStatusThreadLock) {
if (mReadStatusThread == null) {
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
int readBytes = mConnection.bulkTransfer(mInterruptEndpoint,
buffer,
STATUS_BUFFER_SIZE,
100);
if (readBytes != STATUS_BUFFER_SIZE) {
Log.w(TAG, "Could not read initial CTS / DSR / CD / RI status");
} else {
mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
}
mReadStatusThread = new Thread(new Runnable() {
@Override
public void run() {
readStatusThreadFunction();
}
});
mReadStatusThread.setDaemon(true);
mReadStatusThread.start();
}
}
}
/* throw and clear an exception which 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<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC),
new int[] { UsbId.PROLIFIC_PL2303, });
return supportedDevices;
}
}
/* Copyright 2012 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
/**
* Registry of USB vendor/product ID constants.
*
* Culled from various sources; see
* <a href="http://www.linux-usb.org/usb.ids">usb.ids</a> for one listing.
*
* @author mike wakerly (opensource@hoho.com)
*/
public final class UsbId {
public static final int VENDOR_FTDI = 0x0403;
public static final int FTDI_FT232R = 0x6001;
public static final int FTDI_FT231X = 0x6015;
public static final int VENDOR_PX4 = 0x26AC;
public static final int DEVICE_PX4FMU = 0x11;
public static final int VENDOR_ATMEL = 0x03EB;
public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
public static final int VENDOR_ARDUINO = 0x2341;
public static final int ARDUINO_UNO = 0x0001;
public static final int ARDUINO_MEGA_2560 = 0x0010;
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
public static final int ARDUINO_MEGA_ADK = 0x003f;
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
public static final int ARDUINO_UNO_R3 = 0x0043;
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
public static final int ARDUINO_LEONARDO = 0x8036;
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
public static final int VENDOR_LEAFLABS = 0x1eaf;
public static final int LEAFLABS_MAPLE = 0x0004;
public static final int VENDOR_SILAB = 0x10c4;
public static final int SILAB_CP2102 = 0xea60;
public static final int VENDOR_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303;
private UsbId() {
throw new IllegalAccessError("Non-instantiable class.");
}
}
/* 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;
}
/* 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.
*
* <p/>
* You don't need a Prober to use the rest of the library: it is perfectly
* acceptable to instantiate driver instances manually. The Prober simply
* provides convenience functions.
*
* <p/>
* For most drivers, the corresponding {@link #probe(UsbManager, UsbDevice)}
* method will either return an empty list (device unknown / unsupported) or a
* singleton list. However, multi-port drivers may return multiple instances.
*
* @author mike wakerly (opensource@hoho.com)
*/
public enum UsbSerialProber {
// TODO(mikey): Too much boilerplate.
/**
* Prober for {@link FtdiSerialDriver}.
*
* @see FtdiSerialDriver
*/
FTDI_SERIAL {
@Override
public List<UsbSerialDriver> probe(final UsbManager manager, final UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, FtdiSerialDriver.getSupportedDevices())) {
return Collections.emptyList();
}
final 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<UsbSerialDriver> 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<UsbSerialDriver> 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<UsbSerialDriver> 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<UsbSerialDriver> probe(final UsbManager manager, final UsbDevice usbDevice);
/**
* Creates and returns a new {@link UsbSerialDriver} instance for the first
* compatible {@link UsbDevice} found on the bus. If none are found,
* returns {@code null}.
*
* <p/>
* The order of devices is undefined, therefore if there are multiple
* devices on the bus, the chosen device may not be predictable (clients
* should use {@link #findAllDevices(UsbManager)} instead).
*
* @param usbManager the {@link UsbManager} to use.
* @return the first available {@link UsbSerialDriver}, or {@code null} if
* none are available.
*/
public static UsbSerialDriver findFirstDevice(final UsbManager usbManager) {
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
for (final UsbSerialProber prober : values()) {
final List<UsbSerialDriver> probedDevices = prober.probe(usbManager, usbDevice);
if (!probedDevices.isEmpty()) {
return probedDevices.get(0);
}
}
}
return null;
}
/**
* Creates a new {@link UsbSerialDriver} instance for all compatible
* {@link UsbDevice}s found on the bus. If no compatible devices are found,
* the list will be empty.
*
* @param usbManager
* @return
*/
public static List<UsbSerialDriver> findAllDevices(final UsbManager usbManager) {
final List<UsbSerialDriver> result = new ArrayList<UsbSerialDriver>();
Log.i("QGC_UsbSerialProber", "Looking for USB devices");
// For each UsbDevice, call probe() for each prober.
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
Log.i("QGC_UsbSerialProber", "Probing device: " + usbDevice.getDeviceName() + " mid: " + usbDevice.getVendorId() + " pid: " + usbDevice.getDeviceId());
result.addAll(probeSingleDevice(usbManager, usbDevice));
}
return result;
}
/**
* Special method for testing a specific device for driver support,
* returning any compatible driver(s).
*
* <p/>
* Clients should ordinarily use {@link #findAllDevices(UsbManager)}, which
* operates against the entire bus of devices. This method is useful when
* testing against only a single target is desired.
*
* @param usbManager the {@link UsbManager} to use.
* @param usbDevice the device to test against.
* @return a list containing zero or more {@link UsbSerialDriver} instances.
*/
public static List<UsbSerialDriver> probeSingleDevice(final UsbManager usbManager,
UsbDevice usbDevice)
{
final List<UsbSerialDriver> result = new ArrayList<UsbSerialDriver>();
for (final UsbSerialProber prober : values()) {
final List<UsbSerialDriver> probedDevices = prober.probe(usbManager, usbDevice);
result.addAll(probedDevices);
}
return result;
}
/**
* Deprecated; Use {@link #findFirstDevice(UsbManager)}.
*
* @param usbManager
* @return
*/
@Deprecated
public static UsbSerialDriver acquire(final UsbManager usbManager) {
return findFirstDevice(usbManager);
}
/**
* Deprecated; use {@link #probeSingleDevice(UsbManager, UsbDevice)}.
*
* @param usbManager
* @param usbDevice
* @return
*/
@Deprecated
public static UsbSerialDriver acquire(final UsbManager usbManager, final UsbDevice usbDevice) {
final List<UsbSerialDriver> probedDevices = probeSingleDevice(usbManager, usbDevice);
if (!probedDevices.isEmpty()) {
return probedDevices.get(0);
}
return null;
}
/**
* Returns {@code true} if the given device is found in the driver's
* vendor/product map.
*
* @param usbDevice the device to test
* @param supportedDevices map of vendor IDs to product ID(s)
* @return {@code true} if supported
*/
private static boolean testIfSupported(final UsbDevice usbDevice,
final Map<Integer, int[]> supportedDevices) {
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;
}
}
/*
* 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);
}
}
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<UsbSerialDriver> m_devices; // LIST OF CURRENT DEVICES
private static HashMap<Integer, UsbSerialDriver> m_openedDevices; // LIST OF OPENED DEVICES
private static HashMap<Integer, UsbIoManager> m_ioManager; // THREADS FOR LISTENING FOR INCOMING DATA
private static HashMap<Integer, Integer> 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<Integer, UsbSerialDriver>();
m_userData = new HashMap<Integer, Integer>();
m_ioManager = new HashMap<Integer, UsbIoManager>();
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<m_devices.size(); iL++)
{
if (m_openedDevices.get(m_devices.get(iL).getDevice().getDeviceId()) != null)
{
countL++;
break;
}
}
if (m_devices.size() - countL <= 0)
{
//Log.e(TAG, "No open USB devices found");
return null;
}
String[] listL = new String[m_devices.size() - countL];
UsbSerialDriver driverL;
String tempL;
// GET THE DATA ON THE INDIVIDUAL DEVICES SKIPPING THE ONES THAT ARE ALREADY OPEN
countL = 0;
for (iL=0; iL<m_devices.size(); iL++)
{
driverL = m_devices.get(iL);
if (m_openedDevices.get(driverL.getDevice().getDeviceId()) == null)
{
UsbDevice deviceL = driverL.getDevice();
tempL = deviceL.getDeviceName() + ":";
if (driverL instanceof FtdiSerialDriver)
tempL = tempL + "FTDI:";
else if (driverL instanceof CdcAcmSerialDriver)
tempL = tempL + "Cdc Acm:";
else if (driverL instanceof Cp2102SerialDriver)
tempL = tempL + "Cp2102:";
else if (driverL instanceof ProlificSerialDriver)
tempL = tempL + "Prolific:";
else
tempL = tempL + "Unknown:";
tempL = tempL + Integer.toString(deviceL.getProductId()) + ":";
tempL = tempL + Integer.toString(deviceL.getVendorId()) + ":";
listL[countL] = tempL;
countL++;
Log.i(TAG, "Found " + tempL);
}
}
return listL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Open a device based on the name.
//
// Args: nameA - name of the device to open
// userDataA - C++ pointer to the QSerialPort that is trying to open the device. This is
// used by the detector to inform the C++ side if it is unplugged
//
// Returns: ID number of opened port. This number is used to reference the correct port in subsequent
// calls like close(), read(), and write().
//
/////////////////////////////////////////////////////////////////////////////////////////////////
public static int open(String nameA, int userDataA)
{
int idL = BAD_PORT;
Log.i(TAG, "Getting device list");
if (!getCurrentDevices())
return BAD_PORT;
// CHECK THAT PORT IS NOT ALREADY OPENED
if (m_openedDevices != null)
{
for (UsbSerialDriver driverL: m_openedDevices.values())
{
if (nameA.equals(driverL.getDevice().getDeviceName()))
{
Log.e(TAG, "Device already opened");
return BAD_PORT;
}
}
}
else
return BAD_PORT;
if (m_devices == null)
return BAD_PORT;
// OPEN THE DEVICE
try
{
for (int iL=0; iL<m_devices.size(); iL++)
{
Log.i(TAG, "Checking device " + m_devices.get(iL).getDevice().getDeviceName() + " id: " + m_devices.get(iL).getDevice().getDeviceId());
if (nameA.equals(m_devices.get(iL).getDevice().getDeviceName()))
{
idL = m_devices.get(iL).getDevice().getDeviceId();
m_openedDevices.put(idL, m_devices.get(iL));
m_userData.put(idL, userDataA);
if (m_instance.m_UsbReceiver == null)
{
m_instance.m_UsbReceiver= new BroadcastReceiver()
{
public void onReceive(Context contextA, Intent intentA)
{
String actionL = intentA.getAction();
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(actionL))
{
UsbDevice deviceL = (UsbDevice)intentA.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (deviceL != null)
{
if (m_userData.containsKey(deviceL.getDeviceId()))
{
// UsbDeviceJNI.close(deviceL.getDeviceId());
nativeDeviceHasDisconnected(m_userData.get(deviceL.getDeviceId()));
}
}
}
}
};
// TURN ON THE INTENT FILTER SO IT WILL DETECT AN UNPLUG SIGNAL
IntentFilter filterL = new IntentFilter();
filterL.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
m_instance.registerReceiver(m_instance.m_UsbReceiver, filterL);
}
m_openedDevices.get(idL).open();
// START UP THE IO MANAGER TO READ/WRITE DATA TO THE DEVICE
UsbIoManager managerL = new UsbIoManager(m_openedDevices.get(idL), m_Listener, userDataA);
if (managerL == null)
Log.e(TAG, "UsbIoManager instance is null");
m_ioManager.put(idL, managerL);
m_Executor.submit(managerL);
return idL;
}
}
return BAD_PORT;
}
catch(IOException exA)
{
if (idL != BAD_PORT)
{
m_openedDevices.remove(idL);
m_userData.remove(idL);
if(m_ioManager.get(idL) != null)
m_ioManager.get(idL).stop();
m_ioManager.remove(idL);
}
return BAD_PORT;
}
}
public static void startIoManager(int idA)
{
if (m_ioManager.get(idA) != null)
return;
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return;
UsbIoManager managerL = new UsbIoManager(driverL, m_Listener, m_userData.get(idA));
m_ioManager.put(idA, managerL);
m_Executor.submit(managerL);
}
public static void stopIoManager(int idA)
{
if(m_ioManager.get(idA) == null)
return;
m_ioManager.get(idA).stop();
m_ioManager.remove(idA);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Sets the parameters on an open port.
//
// Args: idA - ID number from the open command
// baudRateA - Decimal value of the baud rate. I.E. 9600, 57600, 115200, etc.
// dataBitsA - number of data bits. Valid numbers are 5, 6, 7, 8
// stopBitsA - number of stop bits. Valid numbers are 1, 2
// parityA - No Parity=0, Odd Parity=1, Even Parity=2
//
// Returns: T/F Success/Failure
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
public static boolean setParameters(int idA, int baudRateA, int dataBitsA, int stopBitsA, int parityA)
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return false;
try
{
driverL.setParameters(baudRateA, dataBitsA, stopBitsA, parityA);
return true;
}
catch(IOException eA)
{
return false;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Close the device.
//
// Args: idA - ID number from the open command
//
// Returns: T/F Success/Failure
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
public static boolean close(int idA)
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return false;
try
{
stopIoManager(idA);
m_userData.remove(idA);
m_openedDevices.remove(idA);
driverL.close();
return true;
}
catch(IOException eA)
{
return false;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Write data to the device.
//
// Args: idA - ID number from the open command
// sourceA - byte array of data to write
// timeoutMsecA - amount of time in milliseconds to wait for the write to occur
//
// Returns: number of bytes written
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
public static int write(int idA, byte[] sourceA, int timeoutMSecA)
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return 0;
try
{
return driverL.write(sourceA, timeoutMSecA);
}
catch(IOException eA)
{
return 0;
}
/*
UsbIoManager managerL = m_ioManager.get(idA);
if(managerL != null)
{
managerL.writeAsync(sourceA);
return sourceA.length;
}
else
return 0;
*/
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Determine if a device name if valid. Note, it does not look for devices that are already open
//
// Args: nameA - name of device to look for
//
// Returns: T/F
//
////////////////////////////////////////////////////////////////////////////////////////////////////
public static boolean isDeviceNameValid(String nameA)
{
if (m_devices.size() <= 0)
return false;
for (int iL=0; iL<m_devices.size(); iL++)
{
if (m_devices.get(iL).getDevice().getDeviceName() == nameA)
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Check if the device is open
//
// Args: nameA - name of device
//
// Returns: T/F
//
//////////////////////////////////////////////////////////////////////////////////////////////////////
public static boolean isDeviceNameOpen(String nameA)
{
if (m_openedDevices == null)
return false;
for (UsbSerialDriver driverL: m_openedDevices.values())
{
if (nameA.equals(driverL.getDevice().getDeviceName()))
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set the Data Terminal Ready flag on the device
//
// Args: idA - ID number from the open command
// onA - on=T, off=F
//
// Returns: T/F Success/Failure
//
////////////////////////////////////////////////////////////////////////////////////////////////////
public static boolean setDataTerminalReady(int idA, boolean onA)
{
try
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return false;
driverL.setDTR(onA);
return true;
}
catch(IOException eA)
{
return false;
}
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Set the Request to Send flag
//
// Args: idA - ID number from the open command
// onA - on=T, off=F
//
// Returns: T/F Success/Failure
//
////////////////////////////////////////////////////////////////////////////////////////////
public static boolean setRequestToSend(int idA, boolean onA)
{
try
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return false;
driverL.setRTS(onA);
return true;
}
catch(IOException eA)
{
return false;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// Purge the hardware buffers based on the input and output flags
//
// Args: idA - ID number from the open command
// inputA - input buffer purge. purge=T
// outputA - output buffer purge. purge=T
//
// Returns: T/F Success/Failure
//
///////////////////////////////////////////////////////////////////////////////////////////////
public static boolean purgeBuffers(int idA, boolean inputA, boolean outputA)
{
try
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return false;
return driverL.purgeHwBuffers(inputA, outputA);
}
catch(IOException eA)
{
return false;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Get the native device handle (file descriptor)
//
// Args: idA - ID number from the open command
//
// Returns: device handle
//
///////////////////////////////////////////////////////////////////////////////////////////
public static int getDeviceHandle(int idA)
{
UsbSerialDriver driverL = m_openedDevices.get(idA);
if (driverL == null)
return -1;
UsbDeviceConnection connectL = driverL.getDeviceConnection();
if (connectL == null)
return -1;
else
return connectL.getFileDescriptor();
}
//////////////////////////////////////////////////////////////////////////////////////////////
//
// Get the open usb serial driver for the given id
//
// Args: idA - ID number from the open command
//
// Returns: usb device driver
//
/////////////////////////////////////////////////////////////////////////////////////////////
public static UsbSerialDriver getUsbSerialDriver(int idA)
{
return m_openedDevices.get(idA);
}
}
package org.qgroundcontrol.qgchelper;
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
import com.hoho.android.usbserial.driver.*;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.util.Log;
/**
* Utility class which services a {@link UsbSerialDriver} in its {@link #run()}
* method.
*
* Original author mike wakerly (opensource@hoho.com)
* Modified by Mike Goza
*/
public class UsbIoManager implements Runnable {
private static final int READ_WAIT_MILLIS = 100;
private static final int BUFSIZ = 4096;
private static final String TAG = "QGC_UsbIoManager";
private final UsbSerialDriver mDriver;
private int mUserData;
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private enum State
{
STOPPED,
RUNNING,
STOPPING
}
// Synchronized by 'this'
private State mState = State.STOPPED;
// Synchronized by 'this'
private Listener mListener;
public interface Listener
{
/**
* Called when new incoming data is available.
*/
public void onNewData(byte[] data, int userData);
/**
* Called when {@link SerialInputOutputManager#run()} aborts due to an
* error.
*/
public void onRunError(Exception e, int userData);
}
/**
* Creates a new instance with no listener.
*/
public UsbIoManager(UsbSerialDriver driver)
{
this(driver, null, 0);
Log.i(TAG, "Instance created");
}
/**
* Creates a new instance with the provided listener.
*/
public UsbIoManager(UsbSerialDriver driver, Listener listener, int userData)
{
mDriver = driver;
mListener = listener;
mUserData = userData;
}
public synchronized void setListener(Listener listener)
{
mListener = listener;
}
public synchronized Listener getListener()
{
return mListener;
}
public void writeAsync(byte[] data)
{
synchronized (mWriteBuffer)
{
mWriteBuffer.put(data);
}
}
public synchronized void stop()
{
if (getState() == State.RUNNING)
{
mState = State.STOPPING;
mUserData = 0;
}
}
private synchronized State getState()
{
return mState;
}
/**
* Continuously services the read and write buffers until {@link #stop()} is
* called, or until a driver exception is raised.
*/
@Override
public void run()
{
synchronized (this)
{
if (mState != State.STOPPED)
throw new IllegalStateException("Already running.");
mState = State.RUNNING;
}
try
{
while (true)
{
if (mState != State.RUNNING)
break;
step();
}
}
catch (Exception e)
{
final Listener listener = getListener();
if (listener != null)
listener.onRunError(e, mUserData);
}
finally
{
synchronized (this)
{
mState = State.STOPPED;
}
}
}
private void step() throws IOException
{
// Handle incoming data.
int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS);
if (len > 0)
{
final Listener listener = getListener();
if (listener != null)
{
final byte[] data = new byte[len];
mReadBuffer.get(data, 0, len);
listener.onNewData(data, mUserData);
}
mReadBuffer.clear();
}
/*
// Handle outgoing data.
byte[] outBuff = null;
synchronized (mWriteBuffer)
{
if (mWriteBuffer.position() > 0)
{
len = mWriteBuffer.position();
outBuff = new byte[len];
mWriteBuffer.rewind();
mWriteBuffer.get(outBuff, 0, len);
mWriteBuffer.clear();
}
}
if (outBuff != null)
mDriver.write(outBuff, READ_WAIT_MILLIS);
*/
}
}
......@@ -120,7 +120,11 @@ bool QextSerialPortPrivate::close_sys()
bool QextSerialPortPrivate::flush_sys()
{
#ifdef __android__
::ioctl(fd, TCSADRAIN, &currentTermios);
#else
::tcdrain(fd);
#endif
return true;
}
......
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** 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 <QtCore/qdebug.h>
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
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
** 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 <QtCore/qiodevice.h>
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
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** 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 <errno.h>
#include <stdio.h>
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qsocketnotifier.h>
#include <QtCore/qmap.h>
#include <QtAndroidExtras/QtAndroidExtras>
#include <QtAndroidExtras/QAndroidJniObject>
#include <android/log.h>
#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<jint>(
V_jniClassName,
"open",
"(Ljava/lang/String;I)I",
jnameL.object<jstring>(),
(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<jint>(
V_jniClassName,
"getDeviceHandle",
"(I)I",
deviceId);
if (!hasRegisteredFunctions)
{
// REGISTER THE C++ FUNCTION WITH JNI
QAndroidJniEnvironment envL;
JNINativeMethod methodsL[] {
{"nativeDeviceHasDisconnected", "(I)V", reinterpret_cast<void *>(jniDeviceHasDisconnected)},
{"nativeDeviceNewData", "(I[B)V", reinterpret_cast<void *>(jniDeviceNewData)},
{"nativeDeviceException", "(ILjava/lang/String;)V", reinterpret_cast<void *>(jniDeviceException)}
};
QAndroidJniObject javaClassL(V_jniClassName);
jclass objectClassL = envL->GetObjectClass(javaClassL.object<jobject>());
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<jboolean>(
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<jboolean>(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<void>(V_jniClassName,
"stopIoManager",
"(I)V",
deviceId);
isReadStopped = true;
}
void QSerialPortPrivate::startReadThread()
{
if (!isReadStopped)
return;
QAndroidJniObject::callStaticMethod<void>(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<jboolean>(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<jboolean>(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<jboolean>(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; iL<msecs; iL++)
{
if (origL < readBuffer.size())
return true;
else
QThread::msleep(1);
}
return false;
}
bool QSerialPortPrivate::waitForBytesWritten(int msecs)
{
internalWriteTimeoutMsec = msecs;
bool retL = writeDataOneShot();
internalWriteTimeoutMsec = 0;
return retL;
}
bool QSerialPortPrivate::setBaudRate()
{
setBaudRate(inputBaudRate, QSerialPort::AllDirections);
return true;
}
bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
Q_UNUSED(directions);
return setParameters(baudRate, jniDataBits, jniStopBits, jniParity);
}
bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
int numBitsL = 8;
switch (dataBits)
{
case QSerialPort::Data5:
numBitsL = 5;
break;
case QSerialPort::Data6:
numBitsL = 6;
break;
case QSerialPort::Data7:
numBitsL = 7;
break;
case QSerialPort::Data8:
default:
numBitsL = 8;
break;
}
return setParameters(inputBaudRate, numBitsL, jniStopBits, jniParity);
}
bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
int parL = 0;
switch (parity)
{
case QSerialPort::SpaceParity:
parL = 4;
break;
case QSerialPort::MarkParity:
parL = 3;
break;
case QSerialPort::EvenParity:
parL = 2;
break;
case QSerialPort::OddParity:
parL = 1;
break;
case QSerialPort::NoParity:
default:
parL = 0;
break;
}
return setParameters(inputBaudRate, jniDataBits, jniStopBits, parL);
}
bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
int stopL = 1;
switch (stopBits)
{
case QSerialPort::TwoStop:
stopL = 2;
break;
case QSerialPort::OneAndHalfStop:
stopL = 3;
break;
case QSerialPort::OneStop:
default:
stopL = 1;
break;
}
return setParameters(inputBaudRate, jniDataBits, stopL, jniParity);
}
bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
{
Q_UNUSED(flowControl);
return true;
}
bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy)
{
this->policy = 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<jint>(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<qint32, qint32> 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<qint32> 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
#ifndef QSERIALPORT_ANDROID_P_H
#define QSERIALPORT_ANDROID_P_H
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** 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 <QtCore/qscopedpointer.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qthread.h>
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<qint32> 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
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** 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<QByteArray> 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
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** 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<qint32> QSerialPortInfo::standardBaudRates()
Returns a list of available standard baud rates supported by
the current serial port.
*/
/*!
\fn QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
Returns a list of available serial ports on the system.
*/
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** 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 <QtCore/qlist.h>
#include <QtCore/qscopedpointer.h>
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<qint32> standardBaudRates();
static QList<QSerialPortInfo> availablePorts();
QScopedPointer<QSerialPortInfoPrivate, QSerialPortInfoPrivateDeleter> d_ptr;
private:
QSerialPortInfo(const QSerialPortInfoPrivate &dd);
friend QList<QSerialPortInfo> availablePortsByUdev(bool &ok);
friend QList<QSerialPortInfo> availablePortsBySysfs(bool &ok);
friend QList<QSerialPortInfo> availablePortsByFiltersOfDevices(bool &ok);
};
inline bool QSerialPortInfo::isNull() const
{ return !d_ptr; }
QT_END_NAMESPACE
#endif // QSERIALPORTINFO_H
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** 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 <QtCore/qscopedpointer.h>
#include <QtCore/qstringlist.h>
#include <QtAndroidExtras/QtAndroidExtras>
#include <QtAndroidExtras/QAndroidJniObject>
#include <android/log.h>
QT_BEGIN_NAMESPACE
static const char V_jniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"};
static const char V_TAG[] {"QGC_QSerialPortInfo"};
QList<QSerialPortInfo> availablePortsByFiltersOfDevices()
{
QList<QSerialPortInfo> 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<jobjectArray>();
int countL = envL->GetArrayLength(objArrayL);
for (int iL=0; iL<countL; iL++)
{
QSerialPortInfo infoL;
jstring stringL = (jstring)(envL->GetObjectArrayElement(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<QSerialPortInfo> availablePortsBySysfs()
{
return availablePortsByFiltersOfDevices();
}
QList<QSerialPortInfo> availablePortsByUdev()
{
return availablePortsByFiltersOfDevices();
}
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
return availablePortsByFiltersOfDevices();
}
QList<qint32> QSerialPortInfo::standardBaudRates()
{
return QSerialPortPrivate::standardBaudRates();
}
bool QSerialPortInfo::isBusy() const
{
QAndroidJniObject jstrL = QAndroidJniObject::fromString(d_ptr->portName);
jboolean resultL = QAndroidJniObject::callStaticMethod<jboolean>(
V_jniClassName,
"isDeviceNameOpen",
"(Ljava/lang/String;)Z",
jstrL.object<jstring>());
return resultL;
}
bool QSerialPortInfo::isValid() const
{
QAndroidJniObject jstrL = QAndroidJniObject::fromString(d_ptr->portName);
jboolean resultL = QAndroidJniObject::callStaticMethod<jboolean>(
V_jniClassName,
"isDeviceNameValid",
"(Ljava/lang/String;)Z",
jstrL.object<jstring>());
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
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** 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 <QtCore/qstring.h>
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
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
}
......@@ -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
{
......
......@@ -26,8 +26,10 @@
#include <QRegularExpression>
#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);
......
......@@ -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
......
......@@ -28,7 +28,11 @@
#include "PX4Bootloader.h"
#include <QFile>
#ifdef __android__
#include "qserialportinfo.h"
#else
#include <QSerialPortInfo>
#endif
#include <QDebug>
#include <QTime>
......
......@@ -29,7 +29,11 @@
#include "PX4Bootloader.h"
#include <QTimer>
#ifdef __android__
#include "qserialportinfo.h"
#else
#include <QSerialPortInfo>
#endif
#include <QDebug>
PX4FirmwareUpgradeThreadWorker::PX4FirmwareUpgradeThreadWorker(QObject* parent) :
......
......@@ -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<TCPConfiguration*>(source));
break;
#ifdef UNITTEST_BUILD
#ifndef __android__
case TypeMock:
dupe = new MockConfiguration(dynamic_cast<MockConfiguration*>(source));
break;
#endif
#endif
}
return dupe;
......
......@@ -32,7 +32,11 @@ This file is part of the QGROUNDCONTROL project
#include <QList>
#include <QApplication>
#include <QDebug>
#ifdef __android__
#include "qserialportinfo.h"
#else
#include <QSerialPortInfo>
#endif
#include "LinkManager.h"
#include "MainWindow.h"
......@@ -85,9 +89,11 @@ LinkInterface* LinkManager::createConnectedLink(LinkConfiguration* config)
pLink = new TCPLink(dynamic_cast<TCPConfiguration*>(config));
break;
#ifdef UNITTEST_BUILD
#ifndef __android__
case LinkConfiguration::TypeMock:
pLink = new MockLink(dynamic_cast<MockConfiguration*>(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) {
......
......@@ -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"
......
......@@ -12,8 +12,14 @@
#include <QDebug>
#include <QSettings>
#include <QMutexLocker>
#ifdef __android__
#include "qserialport.h"
#include "qserialportinfo.h"
#else
#include <QSerialPort>
#include <QSerialPortInfo>
#endif
#include "SerialLink.h"
#include "QGC.h"
......
......@@ -40,7 +40,11 @@ class SerialLink;
#include <QThread>
#include <QMutex>
#include <QString>
#ifdef __android__
#include "qserialport.h"
#else
#include <QSerialPort>
#endif
#include <QMetaType>
#include <QLoggingCategory>
......
......@@ -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 <crtdbg.h>
......@@ -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()) {
......
......@@ -28,6 +28,7 @@
#ifndef UNITTEST_H
#define UNITTEST_H
#ifndef __android__
#include <QObject>
#include <QtTest>
......@@ -186,4 +187,5 @@ private:
QSharedPointer<T> _unitTest;
};
#endif // Android
#endif
......@@ -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();
}
......
......@@ -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<QGCUASFileViewMulti> fileWidget;
#ifndef __android__
JoystickInput* joystick; ///< The joystick manager for QGC
#endif
#ifdef QGC_MOUSE_ENABLED_WIN
/** @brief 3d Mouse support (WIN only) */
......
......@@ -32,7 +32,12 @@ This file is part of the QGROUNDCONTROL project
#include <QSettings>
#include <QFileInfoList>
#include <QDebug>
#ifdef __android__
#include "qserialportinfo.h"
#else
#include <QSerialPortInfo>
#endif
#include <SerialConfigurationWindow.h>
#include <SerialLink.h>
......
......@@ -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;
......
......@@ -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:
......
......@@ -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 <QSerialPort>
#include <QSerialPortInfo>
#endif
#include <QIntValidator>
#include <QLineEdit>
......
......@@ -37,7 +37,11 @@ This file is part of the APM_PLANNER project
#define SERIALSETTINGSDIALOG_H
#include <QDialog>
#ifdef __android__
#include "qserialport.h"
#else
#include <QSerialPort>
#endif
namespace Ui {
class SerialSettingsDialog;
......
......@@ -45,8 +45,13 @@ This file is part of the APM_PLANNER project
#include <QStatusBar>
#include <QVBoxLayout>
#include <QComboBox>
#ifdef __android__
#include "qserialport.h"
#include "qserialportinfo.h"
#else
#include <QSerialPort>
#include <QSerialPortInfo>
#endif
TerminalConsole::TerminalConsole(QWidget *parent) :
QWidget(parent),
......
......@@ -39,7 +39,11 @@ This file is part of the APM_PLANNER project
#include "SerialSettingsDialog.h"
#include <QWidget>
#ifdef __android__
#include "qserialport.h"
#else
#include <QSerialPort>
#endif
namespace Ui {
class TerminalConsole;
......
......@@ -3,7 +3,9 @@
#include <QWidget>
#include <QAction>
#ifndef __android__
#include <QtDesigner/QDesignerExportWidget>
#endif
#include "QGCToolWidgetItem.h"
......
......@@ -3,8 +3,9 @@
#include <QWidget>
#include <QAction>
#ifndef __android__
#include <QtDesigner/QDesignerExportWidget>
#endif
#include "QGCToolWidgetItem.h"
class QGCUASParamManagerInterface;
......
......@@ -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();
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment