地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

822 lines
20 KiB

/****************************************************************************
**
** 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.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/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.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $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 kJniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"};
static const char kJTag[] {"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);
}
}
void cleanJavaException()
{
QAndroidJniEnvironment env;
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
}
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, kJTag, "Opening %s", systemLocation.toLatin1().data());
__android_log_print(ANDROID_LOG_INFO, kJTag, "Calling Java Open");
QAndroidJniObject jnameL = QAndroidJniObject::fromString(systemLocation);
cleanJavaException();
deviceId = QAndroidJniObject::callStaticMethod<jint>(
kJniClassName,
"open",
"(Ljava/lang/String;I)I",
jnameL.object<jstring>(),
(jint)this);
cleanJavaException();
isReadStopped = false;
if (deviceId == BAD_PORT)
{
__android_log_print(ANDROID_LOG_ERROR, kJTag, "Error opening %s", systemLocation.toLatin1().data());
q_ptr->setError(QSerialPort::DeviceNotFoundError);
return false;
}
if (!hasRegisteredFunctions)
{
__android_log_print(ANDROID_LOG_INFO, kJTag, "Registering Native Functions");
// REGISTER THE C++ FUNCTION WITH JNI
JNINativeMethod javaMethods[] {
{"nativeDeviceHasDisconnected", "(I)V", reinterpret_cast<void *>(jniDeviceHasDisconnected)},
{"nativeDeviceNewData", "(I[B)V", reinterpret_cast<void *>(jniDeviceNewData)},
{"nativeDeviceException", "(ILjava/lang/String;)V", reinterpret_cast<void *>(jniDeviceException)}
};
QAndroidJniEnvironment jniEnv;
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
QAndroidJniObject javaClass(kJniClassName);
if(!javaClass.isValid()) {
__android_log_print(ANDROID_LOG_ERROR, kJTag, "Java class %s not valid", kJniClassName);
return false;
}
jclass objectClass = jniEnv->GetObjectClass(javaClass.object<jobject>());
jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));
jniEnv->DeleteLocalRef(objectClass);
hasRegisteredFunctions = true;
__android_log_print(ANDROID_LOG_INFO, kJTag, "Native Functions Registered");
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
if(val < 0) {
__android_log_print(ANDROID_LOG_ERROR, kJTag, "Error registering methods");
q_ptr->setError(QSerialPort::OpenError);
return false;
}
}
__android_log_print(ANDROID_LOG_INFO, kJTag, "Calling Java getDeviceHandle");
cleanJavaException();
descriptor = QAndroidJniObject::callStaticMethod<jint>(
kJniClassName,
"getDeviceHandle",
"(I)I",
deviceId);
cleanJavaException();
if (rwMode == QIODevice::WriteOnly)
stopReadThread();
return true;
}
void QSerialPortPrivate::close()
{
if (deviceId == BAD_PORT)
return;
__android_log_print(ANDROID_LOG_INFO, kJTag, "Closing %s", systemLocation.toLatin1().data());
cleanJavaException();
jboolean resultL = QAndroidJniObject::callStaticMethod<jboolean>(
kJniClassName,
"close",
"(I)Z",
deviceId);
cleanJavaException();
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;
}
cleanJavaException();
jboolean resultL = QAndroidJniObject::callStaticMethod<jboolean>(
kJniClassName,
"setParameters",
"(IIIII)Z",
deviceId,
baudRateA,
dataBitsA,
stopBitsA,
parityA);
cleanJavaException();
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;
cleanJavaException();
QAndroidJniObject::callStaticMethod<void>(
kJniClassName,
"stopIoManager",
"(I)V",
deviceId);
cleanJavaException();
isReadStopped = true;
}
void QSerialPortPrivate::startReadThread()
{
if (!isReadStopped)
return;
cleanJavaException();
QAndroidJniObject::callStaticMethod<void>(
kJniClassName,
"startIoManager",
"(I)V",
deviceId);
cleanJavaException();
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;
}
cleanJavaException();
bool res = QAndroidJniObject::callStaticMethod<jboolean>(
kJniClassName,
"setDataTerminalReady",
"(IZ)Z",
deviceId,
set);
cleanJavaException();
return res;
}
bool QSerialPortPrivate::setRequestToSend(bool set)
{
if (deviceId == BAD_PORT)
{
q_ptr->setError(QSerialPort::NotOpenError);
return false;
}
cleanJavaException();
bool res = QAndroidJniObject::callStaticMethod<jboolean>(
kJniClassName,
"setRequestToSend",
"(IZ)Z",
deviceId,
set);
cleanJavaException();
return res;
}
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;
}
cleanJavaException();
bool res = QAndroidJniObject::callStaticMethod<jboolean>(
kJniClassName,
"purgeBuffers",
"(IZZ)Z",
deviceId,
inputL,
outputL);
cleanJavaException();
return res;
}
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 jniEnv;
jbyteArray jarrayL = jniEnv->NewByteArray(maxSize);
jniEnv->SetByteArrayRegion(jarrayL, 0, maxSize, (jbyte *)data);
if (jniEnv->ExceptionCheck())
jniEnv->ExceptionClear();
int resultL = QAndroidJniObject::callStaticMethod<jint>(
kJniClassName,
"write",
"(I[BI)I",
deviceId,
jarrayL,
internalWriteTimeoutMsec);
if (jniEnv->ExceptionCheck())
{
jniEnv->ExceptionClear();
q_ptr->setErrorString(QStringLiteral("Writing to the device threw an exception"));
jniEnv->DeleteLocalRef(jarrayL);
return 0;
}
jniEnv->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