diff --git a/.gitignore b/.gitignore index cf34ac8aadac498e894176d70c9a9c87d494f982..3184e1aaa05fe59a4a97865d24e7f9accf941260 100644 --- a/.gitignore +++ b/.gitignore @@ -1,55 +1,52 @@ -*.swp -*.nfs -CMakeFiles -*Makefile* -tags -build*/ -Info.plist -obj -.DS_Store -*.log -*~ -*~.skp -bin/*.exe -bin/*.txt -bin/mac -*pro.user* -qrc_*.cpp -*.Debug -*.Release -tmp -debug -release -qgroundcontrol -mavlinkgen-build-desktop -qgroundcontrol.xcodeproj/** -doc/html -doc/doxy.log -deploy/mac -deploy/linux -deploy/qgroundcontrol* -controller_log* -user_config.pri -*.app -*.ncb -*.vcproj -*.vcxproj* -*.sdf -*.ipch -*.pdb -*.sln -*.sln -*.vcproj -*.user -*.ncb -*.idb -*.project -*.cproject -*.sln -*.suo -*.uhf.txt -*.opensdf - -thirdParty/qserialport-build-desktop/ -thirdParty/qserialport/bin/ -thirdParty/qserialport/lib/ +*.swp +*.nfs +CMakeFiles +*Makefile* +tags +build*/ +Info.plist +obj +.DS_Store +*.log +*~ +*~.skp +bin/*.exe +bin/*.txt +bin/mac +*pro.user* +qrc_*.cpp +*.Debug +*.Release +tmp +debug +release +qgroundcontrol +mavlinkgen-build-desktop +qgroundcontrol.xcodeproj/** +doc/html +doc/doxy.log +deploy/mac +deploy/linux +deploy/qgroundcontrol* +controller_log* +user_config.pri +*.app +*.ncb +*.vcproj +*.vcxproj* +*.sdf +*.ipch +*.pdb +*.sln +*.sln +*.vcproj +*.user +*.ncb +*.idb +*.project +*.cproject +*.sln +*.suo +*.uhf.txt +*.opensdf +apmplanner2.xcodeproj/ diff --git a/files/images/devices/AC-0004-11-2.jpg b/files/images/devices/AC-0004-11-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..334486b6756e6b2671c1a2dd1099f2c051e4a20c Binary files /dev/null and b/files/images/devices/AC-0004-11-2.jpg differ diff --git a/files/images/devices/BR-0004-03-2.jpg b/files/images/devices/BR-0004-03-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0126646ef48942d00ed34f2b0e720b26a308f155 Binary files /dev/null and b/files/images/devices/BR-0004-03-2.jpg differ diff --git a/files/images/devices/BR-0016-01-3T.jpg b/files/images/devices/BR-0016-01-3T.jpg new file mode 100644 index 0000000000000000000000000000000000000000..534eba3f0b7cfa4f16f7aeab02f410bc489bc50b Binary files /dev/null and b/files/images/devices/BR-0016-01-3T.jpg differ diff --git a/files/images/devices/BR-APMPWRDEAN-2.jpg b/files/images/devices/BR-APMPWRDEAN-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62a6a83b8380283f52d1b9981cd960711a2e8630 Binary files /dev/null and b/files/images/devices/BR-APMPWRDEAN-2.jpg differ diff --git a/files/images/devices/BR-HMC5883-01-2.jpg b/files/images/devices/BR-HMC5883-01-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f695795f6f93082d0e4a9b588aef3e9f515ff133 Binary files /dev/null and b/files/images/devices/BR-HMC5883-01-2.jpg differ diff --git a/files/images/devices/MinimOSD.jpg b/files/images/devices/MinimOSD.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b24c7e4a9759278435edcefe778e51765177d26e Binary files /dev/null and b/files/images/devices/MinimOSD.jpg differ diff --git a/files/images/devices/Shutter.png b/files/images/devices/Shutter.png new file mode 100644 index 0000000000000000000000000000000000000000..0362734d5762771d2b98bcfe55fe6c08138cf412 Binary files /dev/null and b/files/images/devices/Shutter.png differ diff --git a/files/images/devices/cameraGimalPitch1.png b/files/images/devices/cameraGimalPitch1.png new file mode 100644 index 0000000000000000000000000000000000000000..158429893b5aa82506f4ca902b7d8acdec03253f Binary files /dev/null and b/files/images/devices/cameraGimalPitch1.png differ diff --git a/files/images/devices/cameraGimalRoll1.png b/files/images/devices/cameraGimalRoll1.png new file mode 100644 index 0000000000000000000000000000000000000000..bff678c9e7adc2264732f2df1d2bdfd29e7e3368 Binary files /dev/null and b/files/images/devices/cameraGimalRoll1.png differ diff --git a/files/images/devices/cameraGimalYaw.png b/files/images/devices/cameraGimalYaw.png new file mode 100644 index 0000000000000000000000000000000000000000..0375add2c31bf2c7a5926ce864037bd43a550068 Binary files /dev/null and b/files/images/devices/cameraGimalYaw.png differ diff --git a/libs/serialport/doc/images/blockingmaster-example.png b/libs/serialport/doc/images/blockingmaster-example.png new file mode 100644 index 0000000000000000000000000000000000000000..44aa5ecfa894a78074ce7e89a331d0006be6d834 Binary files /dev/null and b/libs/serialport/doc/images/blockingmaster-example.png differ diff --git a/libs/serialport/doc/images/blockingslave-example.png b/libs/serialport/doc/images/blockingslave-example.png new file mode 100644 index 0000000000000000000000000000000000000000..44aa39394d3dbfbf8a5d519a428d60230b188805 Binary files /dev/null and b/libs/serialport/doc/images/blockingslave-example.png differ diff --git a/libs/serialport/doc/images/cenumerator-example.png b/libs/serialport/doc/images/cenumerator-example.png new file mode 100644 index 0000000000000000000000000000000000000000..03792e71dbe3c6f291c4c6c0533f7e30286dccb6 Binary files /dev/null and b/libs/serialport/doc/images/cenumerator-example.png differ diff --git a/libs/serialport/doc/images/enumerator-example.png b/libs/serialport/doc/images/enumerator-example.png new file mode 100644 index 0000000000000000000000000000000000000000..c4add83896d3b144c99945384060b0f22bd962e8 Binary files /dev/null and b/libs/serialport/doc/images/enumerator-example.png differ diff --git a/libs/serialport/doc/images/terminal-example.png b/libs/serialport/doc/images/terminal-example.png new file mode 100644 index 0000000000000000000000000000000000000000..28aa366709c8e54968f54a75d4c3569e98c0cdc5 Binary files /dev/null and b/libs/serialport/doc/images/terminal-example.png differ diff --git a/libs/serialport/doc/qtserialport.qdocconf b/libs/serialport/doc/qtserialport.qdocconf new file mode 100644 index 0000000000000000000000000000000000000000..f095c2f18b0456edc4461bb19110a69964d3e03b --- /dev/null +++ b/libs/serialport/doc/qtserialport.qdocconf @@ -0,0 +1,37 @@ +include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) + +project = QtSerialPort +description = Qt Serial Port Reference Documentation +url = http://qt-project.org/doc/qt-$QT_VER/qtserialport +version = $QT_VERSION + +qhp.projects = QtSerialPort + +qhp.QtSerialPort.file = qtserialport.qhp +qhp.QtSerialPort.namespace = org.qt-project.qtserialport.$QT_VERSION_TAG +qhp.QtSerialPort.virtualFolder = qtserialport +qhp.QtSerialPort.indexTitle = Qt Serial Port +qhp.QtSerialPort.indexRoot = + +qhp.QtSerialPort.filterAttributes = qtserialport $QT_VERSION qtrefdoc +qhp.QtSerialPort.customFilters.Qt.name = QtSerialPort $QT_VERSION +qhp.QtSerialPort.customFilters.Qt.filterAttributes = qtserialport $QT_VERSION + +qhp.QtSerialPort.subprojects = classes examples + +qhp.QtSerialPort.subprojects.classes.title = C++ Classes +qhp.QtSerialPort.subprojects.classes.indexTitle = Qt Serial Port C++ Classes +qhp.QtSerialPort.subprojects.classes.selectors = class fake:headerfile +qhp.QtSerialPort.subprojects.classes.sortPages = true + +qhp.QtSerialPort.subprojects.examples.title = Examples +qhp.QtSerialPort.subprojects.examples.indexTitle = Qt Serial Port Examples +qhp.QtSerialPort.subprojects.examples.selectors = fake:example +qhp.QtSerialPort.subprojects.examples.sortPages = true + +headerdirs += .. +sourcedirs += .. +exampledirs += ../../../examples/serialport +imagedirs += images + +depends += qtcore qtdoc diff --git a/libs/serialport/doc/src/index.qdoc b/libs/serialport/doc/src/index.qdoc new file mode 100644 index 0000000000000000000000000000000000000000..ae5faebc964a4f025729be4039ed3e8de440797c --- /dev/null +++ b/libs/serialport/doc/src/index.qdoc @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 - 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qtserialport-index.html + \title Qt Serial Port + \brief Provides API to make the serial programming simple and portable. + + Qt Serial Port provides the basic functionality, which includes + configuring, I/O operations, get and set control signals of the + RS-232 pinouts. + + The following are not supported by this module: + \list + \li Terminal features such as echo, control CR/LF, and so on. + \li Text mode. + \li Configuring timeouts and delays while reading. + \li Tracking and notification when the state of RS-232 pinout signals change. + \endlist + + To use these classes in your application, use the following include + statement: + + \code + #include + \endcode + + To link against the module, add this line to your \l qmake \c + .pro file: + + \code + QT += serialport + \endcode + + \section1 Related information + \list + \li \l{Qt Serial Port C++ Classes}{C++ Classes} + \li \l{Qt Serial Port Examples}{Examples} + \endlist + +*/ diff --git a/libs/serialport/doc/src/qtserialport-module.qdoc b/libs/serialport/doc/src/qtserialport-module.qdoc new file mode 100644 index 0000000000000000000000000000000000000000..b0fc506e52d3988695eb65b19f8bfcde4abe5200 --- /dev/null +++ b/libs/serialport/doc/src/qtserialport-module.qdoc @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2011 - 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module QtSerialPort + \title Qt Serial Port C++ Classes + \brief List of C++ classes that enable access to a serial port. + + To use these classes in your application, use the following include + statement: + + \code + #include + \endcode + + To link against the module, add this line to your \l qmake \c + .pro file: + + \code + QT += serialport + \endcode +*/ diff --git a/libs/serialport/doc/style/style.css b/libs/serialport/doc/style/style.css new file mode 100644 index 0000000000000000000000000000000000000000..df84049f12a08d68086728ae454e72ba6ecd75da --- /dev/null +++ b/libs/serialport/doc/style/style.css @@ -0,0 +1,137 @@ +a:link, a:visited { + color: #00732F; + text-decoration: none; + font-weight: bold; +} + +body { + font: normal 400 14px/1.2 Arial; + margin-top: 85px; +} + +h1 { + margin: 0; +} + +h2 { + font: 500 20px/1.2 Arial; +} + +h3.fn, span.fn { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border-width: 1px; + border-style: solid; + border-color: #E6E6E6; + word-spacing: 3px; + padding: 3px 5px; +} + +table, pre { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + font-size: 12px; + line-height: 1.2; + margin-bottom: 25px; + margin-left: 15px; +} + +table td { + padding: 3px 15px 3px 20px; +} + +table tr.even { + background-color: white; + color: #66666E; +} + +table tr.odd { + background-color: #F6F6F6; + color: #66666E; +} + +li { + margin-bottom: 10px; + padding-left: 12px; +} + +.cpp { + display: block; + margin: 10; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + padding: 20px 0 20px 0; +} + +.footer { + margin-top: 50px; +} + +.memItemLeft { + padding-right: 3px; +} + +.memItemRight { + padding: 3px 15px 3px 0; +} + +.qml { + display: block; + margin: 10; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + padding: 20px 0 20px 0; +} + +.qmldefault { + padding-left: 5px; + float: right; + color: red; +} + +.qmlreadonly { + padding-left: 5px; + float: right; + color: #254117; +} + +.rightAlign { + padding: 3px 5px 3px 10px; + text-align: right; +} + +.title { + background-color: white; + color: #44A51C; + font-family: Verdana; + font-size: 35px; + font-weight: normal; + left: 0; + padding-bottom: 5px; + padding-left: 16px; + padding-top: 20px; + position: absolute; + right: 0; + top: 0; +} + +.toc { + float: right; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #DDD; + margin: 0 20px 10px 10px; + padding: 20px 15px 20px 20px; + height: auto; + width: 200px; +} diff --git a/libs/serialport/qserialport.cpp b/libs/serialport/qserialport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96f06d4bd9d3f17d644bcca0b8cf4b15035ae523 --- /dev/null +++ b/libs/serialport/qserialport.cpp @@ -0,0 +1,1167 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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.h" +#include "qserialportinfo.h" + +#ifdef Q_OS_WIN +#include "qserialport_win_p.h" +#elif defined (Q_OS_SYMBIAN) +#include "qserialport_symbian_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 + +QT_BEGIN_NAMESPACE + +QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q) + : readBufferMaxSize(0) + , readBuffer(SERIALPORT_BUFFERSIZE) + , writeBuffer(SERIALPORT_BUFFERSIZE) + , error(QSerialPort::NoError) + , inputBaudRate(0) + , outputBaudRate(0) + , dataBits(QSerialPort::UnknownDataBits) + , parity(QSerialPort::UnknownParity) + , stopBits(QSerialPort::UnknownStopBits) + , flow(QSerialPort::UnknownFlowControl) + , policy(QSerialPort::IgnorePolicy) + , settingsRestoredOnClose(true) + , 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. + + The status of the control pinout signals is determined with the + isDataTerminalReady(), isRequestToSend, and pinoutSignals() methods. To + change the control line status, use the setDataTerminalReady(), and + setRequestToSend() methods. + + 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. + + \sa QSerialPort::baudRate +*/ + +/*! + \enum QSerialPort::DataBits + + This enum describes the number of data bits used. + + \value Data5 Five bits. + \value Data6 Six bits. + \value Data7 Seven bits + \value Data8 Eight bits. + \value UnknownDataBits Unknown number of bits. + + \sa QSerialPort::dataBits +*/ + +/*! + \enum QSerialPort::Parity + + This enum describes the parity scheme used. + + \value NoParity No parity. + \value EvenParity Even parity. + \value OddParity Odd parity. + \value SpaceParity Space parity. + \value MarkParity Mark parity. + \value UnknownParity Unknown parity. + + \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. + \value TwoStop 2 stop bits. + \value UnknownStopBits Unknown number of stop bit. + + \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. + + \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). + \value ReceivedDataSignal RxD (Received Data). + \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 + + 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 to 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 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 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() +{ + /**/ + close(); + delete d_ptr; +} + +/*! + Sets the \a name of the serial port. + + The name of the serial port can be passed on 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 = QSerialPortPrivate::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 = QSerialPortPrivate::portNameToSystemLocation(serialPortInfo.systemLocation()); +} + +/*! + Returns the name set by setPort() or to the QSerialPort constructors. + This name is short, i.e. it extract and convert out from the internal + variable system location of the device. Conversion algorithm is + platform specific: + \table + \header + \li Platform + \li Brief Description + \row + \li Windows + \li Removes the prefix "\\\\.\\" from the system location + and returns the remainder of the string. + \row + \li Windows CE + \li Removes the postfix ":" 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 GNU/Linux + \li Removes the prefix "/dev/" from the system location + and returns the remainder of the string. + \row + \li Mac OSX + \li Removes the prefix "/dev/cu." and "/dev/tty." from the + system location and returns the remainder of the string. + \row + \li Other *nix + \li The same as for GNU/Linux. + \endtable + + \sa setPort(), QSerialPortInfo::portName() +*/ +QString QSerialPort::portName() const +{ + Q_D(const QSerialPort); + return QSerialPortPrivate::portNameFromSystemLocation(d->systemLocation); +} + +/*! + \reimp + + Opens the serial port using OpenMode \a mode, and then returns true if + successful; otherwise returns false with and sets an error code which can be + obtained by calling the error() method. + + \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)) { + QIODevice::open(mode); + + d->dataTerminalReady = isDataTerminalReady(); + d->requestToSend = isRequestToSend(); + + return true; + } + return false; +} + +/*! + \reimp + + \sa QIODevice::close() +*/ +void QSerialPort::close() +{ + Q_D(QSerialPort); + if (!isOpen()) { + return; + } + + QIODevice::close(); + d->close(); +} + +/*! + \property QSerialPort::settingsRestoredOnClose + \brief the flag which allows to restore the previous settings while closing + the serial port. + + If this flag is true, the settings will be restored; otherwise not. + The default state of the QSerialPort class is configured to restore the + settings. +*/ +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; +} + +/*! + \fn void QSerialPort::settingsRestoredOnCloseChanged(bool restore) + + This signal is emitted after the flag which allows to restore the + previous settings while closing the serial port has been changed. The new + flag which allows 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, 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. + + \warning Only the AllDirections flag is support for setting this property on + Windows, Windows CE, and Symbian. + + \warning Returns equal baud rate in any direction on Windows, Windows CE, and + Symbian. +*/ +bool QSerialPort::setBaudRate(qint32 baudRate, Directions dir) +{ + Q_D(QSerialPort); + + if (d->setBaudRate(baudRate, dir)) { + if (dir & QSerialPort::Input) { + if (d->inputBaudRate != baudRate) + d->inputBaudRate = baudRate; + else + dir &= ~QSerialPort::Input; + } + + if (dir & QSerialPort::Output) { + if (d->outputBaudRate != baudRate) + d->outputBaudRate = baudRate; + else + dir &= ~QSerialPort::Output; + } + + if (dir) + emit baudRateChanged(baudRate, dir); + + return true; + } + + return false; +} + +qint32 QSerialPort::baudRate(Directions dir) const +{ + Q_D(const QSerialPort); + if (dir == QSerialPort::AllDirections) + return d->inputBaudRate == d->outputBaudRate ? + d->inputBaudRate : QSerialPort::UnknownBaud; + return dir & QSerialPort::Input ? d->inputBaudRate : d->outputBaudRate; +} + +/*! + \fn void QSerialPort::baudRateChanged(qint32 baudRate, Directions dir) + + This signal is emitted after the baud rate has been changed. The new baud + rate is passed as \a baudRate and directions as \a dir. + + \sa QSerialPort::baudRate +*/ + +/*! + \property QSerialPort::dataBits + \brief the data bits in a frame + + If the setting is successful, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setDataBits(DataBits dataBits) +{ + Q_D(QSerialPort); + + if (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, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setParity(Parity parity) +{ + Q_D(QSerialPort); + + if (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, returns true; otherwise returns false and + sets an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setStopBits(StopBits stopBits) +{ + Q_D(QSerialPort); + + if (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, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setFlowControl(FlowControl flow) +{ + Q_D(QSerialPort); + + if (d->setFlowControl(flow)) { + if (d->flow != flow) { + d->flow = flow; + emit flowControlChanged(d->flow); + } + return true; + } + + return false; +} + +QSerialPort::FlowControl QSerialPort::flowControl() const +{ + Q_D(const QSerialPort); + return d->flow; +} + +/*! + \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 + + If the setting is successful, returns true; otherwise returns false. + If the flag is true then the DTR signal is set to high; otherwise low. + + \sa pinoutSignals() +*/ +bool QSerialPort::setDataTerminalReady(bool set) +{ + Q_D(QSerialPort); + + bool retval = d->setDataTerminalReady(set); + if (retval && (d->dataTerminalReady != set)) { + d->dataTerminalReady = set; + emit dataTerminalReadyChanged(set); + } + + return retval; +} + +bool QSerialPort::isDataTerminalReady() +{ + Q_D(const 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 + + If the setting is successful, returns true; otherwise returns false. + If the flag is true then the RTS signal is set to high; otherwise low. + + \sa pinoutSignals() +*/ +bool QSerialPort::setRequestToSend(bool set) +{ + Q_D(QSerialPort); + + bool retval = d->setRequestToSend(set); + if (retval && (d->requestToSend != set)) { + d->requestToSend = set; + emit requestToSendChanged(set); + } + + return retval; +} + +bool QSerialPort::isRequestToSend() +{ + Q_D(const 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 that, 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. + + \sa isDataTerminalReady(), isRequestToSend, setDataTerminalReady(), + setRequestToSend() +*/ +QSerialPort::PinoutSignals QSerialPort::pinoutSignals() +{ + Q_D(const QSerialPort); + 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. + + \sa write(), waitForBytesWritten() +*/ +bool QSerialPort::flush() +{ + Q_D(QSerialPort); + return d->flush(); +} + +/*! + Discards all characters from the output or input buffer, depending on + a given direction \a dir. Including clear an internal class buffers and + the UART (driver) buffers. Also terminate pending read or write operations. + If successful, returns true; otherwise returns false. +*/ +bool QSerialPort::clear(Directions dir) +{ + Q_D(QSerialPort); + if (dir & Input) + d->readBuffer.clear(); + if (dir & Output) + d->writeBuffer.clear(); + return d->clear(dir); +} + +/*! + \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->bytesAvailable() == 0)); +} + +/*! + \property QSerialPort::dataErrorPolicy + \brief the error policy how the process receives the character in case of + parity error detection. + + If the setting is successful, returns true; otherwise returns false. The + default policy set is IgnorePolicy. +*/ +bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy) +{ + Q_D(QSerialPort); + + 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; +} + +/*! + \fn void QSerialPort::dataErrorPolicyChanged(DataErrorPolicy policy) + + This signal is emitted after the error policy how the process receives the + character in case of parity error detection has been changed. The new error + policy 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 erroris + 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. Exceptionally, 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 causes that the application runs 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->bytesAvailable() + 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->writeBuffer.size() + 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->bytesAvailable() > 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); +} + +/*! + \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. + + \sa setBreakEnabled() +*/ +bool QSerialPort::sendBreak(int duration) +{ + Q_D(QSerialPort); + 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. + + \sa sendBreak() +*/ +bool QSerialPort::setBreakEnabled(bool set) +{ + Q_D(QSerialPort); + return d->setBreakEnabled(set); +} + +/*! + \reimp +*/ +qint64 QSerialPort::readData(char *data, qint64 maxSize) +{ + Q_D(QSerialPort); + return d->readFromBuffer(data, maxSize); +} + +/*! + \reimp +*/ +qint64 QSerialPort::readLineData(char *data, qint64 maxSize) +{ + return QIODevice::readLineData(data, maxSize); +} + +/*! + \reimp +*/ +qint64 QSerialPort::writeData(const char *data, qint64 maxSize) +{ + Q_D(QSerialPort); + return d->writeToBuffer(data, maxSize); +} + +void QSerialPort::setError(QSerialPort::SerialPortError serialPortError, const QString &errorString) +{ + Q_D(QSerialPort); + + d->error = serialPortError; + + if (errorString.isNull()) + setErrorString(qt_error_string(-1)); + else + setErrorString(errorString); + + emit error(serialPortError); +} + +#include "moc_qserialport.cpp" + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport.h b/libs/serialport/qserialport.h new file mode 100644 index 0000000000000000000000000000000000000000..8a2842fe0dd7630970237eebd1d6dba3131b6b95 --- /dev/null +++ b/libs/serialport/qserialport.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2013 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_H +#define QSERIALPORT_H + +#include + +#include +//#include +QT_BEGIN_NAMESPACE + +class QSerialPortInfo; +class QSerialPortPrivate; + +class Q_SERIALPORT_EXPORT QSerialPort : public QIODevice +{ + Q_OBJECT + + 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) + Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy NOTIFY dataErrorPolicyChanged) + 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) + Q_PROPERTY(bool settingsRestoredOnClose READ settingsRestoredOnClose WRITE setSettingsRestoredOnClose NOTIFY settingsRestoredOnCloseChanged) + + Q_ENUMS( Directions Rate DataBits Parity StopBits FlowControl PinoutSignals DataErrorPolicy SerialPortError ) + +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) + + enum DataErrorPolicy { + SkipPolicy, + PassZeroPolicy, + IgnorePolicy, + StopReceivingPolicy, + UnknownPolicy = -1 + }; + + enum SerialPortError { + NoError, + DeviceNotFoundError, + PermissionError, + OpenError, + ParityError, + FramingError, + BreakConditionError, + WriteError, + ReadError, + ResourceError, + UnsupportedOperationError, + UnknownError + }; + + explicit QSerialPort(QObject *parent = 0); + explicit QSerialPort(const QString &name, QObject *parent = 0); + explicit QSerialPort(const QSerialPortInfo &info, QObject *parent = 0); + 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; + + void setSettingsRestoredOnClose(bool restore); + bool settingsRestoredOnClose() const; + + bool setBaudRate(qint32 baudRate, Directions dir = AllDirections); + qint32 baudRate(Directions dir = 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 flow); + FlowControl flowControl() const; + + bool setDataTerminalReady(bool set); + bool isDataTerminalReady(); + + bool setRequestToSend(bool set); + bool isRequestToSend(); + + PinoutSignals pinoutSignals(); + + bool flush(); + bool clear(Directions dir = AllDirections); + bool atEnd() const Q_DECL_OVERRIDE; + + bool setDataErrorPolicy(DataErrorPolicy policy = IgnorePolicy); + DataErrorPolicy dataErrorPolicy() const; + + 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); + +Q_SIGNALS: + void baudRateChanged(qint32 baudRate, QSerialPort::Directions dir); + void dataBitsChanged(QSerialPort::DataBits dataBits); + void parityChanged(QSerialPort::Parity parity); + void stopBitsChanged(QSerialPort::StopBits stopBits); + void flowControlChanged(QSerialPort::FlowControl flow); + 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_DECLARE_PRIVATE(QSerialPort) + Q_DISABLE_COPY(QSerialPort) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::PinoutSignals) + +QT_END_NAMESPACE + +#endif // QSERIALPORT_H diff --git a/libs/serialport/qserialport.pri b/libs/serialport/qserialport.pri new file mode 100644 index 0000000000000000000000000000000000000000..9de6a7ab05f6d50072774e49bc7adb53c0609e04 --- /dev/null +++ b/libs/serialport/qserialport.pri @@ -0,0 +1,58 @@ +INCLUDEPATH += $$PWD + +unix { + CONFIG += link_pkgconfig + + packagesExist(libudev) { + DEFINES += HAVE_LIBUDEV + PKGCONFIG += libudev + } +} + +PUBLIC_HEADERS += \ + $$PWD/qserialportglobal.h \ + $$PWD/qserialport.h \ + $$PWD/qserialportinfo.h + +PRIVATE_HEADERS += \ + $$PWD/qserialport_p.h \ + $$PWD/qserialportinfo_p.h + +SOURCES += \ + $$PWD/qserialport.cpp \ + $$PWD/qserialportinfo.cpp + +win32 { + PRIVATE_HEADERS += \ + $$PWD/qserialport_win_p.h + + SOURCES += \ + $$PWD/qserialport_win.cpp \ + $$PWD/qserialportinfo_win.cpp + + LIBS += -lsetupapi -ladvapi32 + +} + +unix:!symbian { + PRIVATE_HEADERS += \ + $$PWD/qttylocker_unix_p.h \ + $$PWD/qserialport_unix_p.h + + SOURCES += \ + $$PWD/qttylocker_unix.cpp \ + $$PWD/qserialport_unix.cpp \ + $$PWD/qserialportinfo_unix.cpp + + macx { + SOURCES += $$PWD/qserialportinfo_mac.cpp + + LIBS += -framework IOKit -framework CoreFoundation + } else { + linux*:contains( DEFINES, HAVE_LIBUDEV ) { + LIBS += -ludev + } + } +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/libs/serialport/qserialport_p.h b/libs/serialport/qserialport_p.h new file mode 100644 index 0000000000000000000000000000000000000000..abd9cb633d5d4fec21196286fa4158695cfbb52a --- /dev/null +++ b/libs/serialport/qserialport_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_P_H +#define QSERIALPORT_P_H + +#include "qserialport.h" + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else +#include "qt4support/qringbuffer_p.h" +#endif + +QT_BEGIN_NAMESPACE + +class QSerialPortPrivateData +{ + Q_DECLARE_PUBLIC(QSerialPort) +public: + enum IoConstants { + ReadChunkSize = 512, + WriteChunkSize = 512 + }; + + QSerialPortPrivateData(QSerialPort *q); + int timeoutValue(int msecs, int elapsed); + + qint64 readBufferMaxSize; + QRingBuffer readBuffer; + QRingBuffer writeBuffer; + QSerialPort::SerialPortError error; + QString systemLocation; + qint32 inputBaudRate; + qint32 outputBaudRate; + QSerialPort::DataBits dataBits; + QSerialPort::Parity parity; + QSerialPort::StopBits stopBits; + QSerialPort::FlowControl flow; + QSerialPort::DataErrorPolicy policy; + bool dataTerminalReady; + bool requestToSend; + bool settingsRestoredOnClose; + QSerialPort * const q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_P_H diff --git a/libs/serialport/qserialport_symbian.cpp b/libs/serialport/qserialport_symbian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bba5a4d86c4ef90e52266cbf35a7ded003a82ae --- /dev/null +++ b/libs/serialport/qserialport_symbian.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** 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_symbian_p.h" + +#include + +#include +//#include +#include + +QT_BEGIN_NAMESPACE + +// Physical device driver. +#ifdef __WINS__ +_LIT(KPddName, "ECDRV"); +#else // defined (__EPOC32__) +_LIT(KPddName, "EUART"); +#endif + +// Logical device driver. +_LIT(KLddName,"ECOMM"); + +// Modules names. +_LIT(KRS232ModuleName, "ECUART"); +_LIT(KBluetoothModuleName, "BTCOMM"); +_LIT(KInfraRedModuleName, "IRCOMM"); +_LIT(KACMModuleName, "ECACM"); + +// Return false on error load. +static bool loadDevices() +{ + TInt r = KErrNone; +#ifdef __WINS__ + RFs fileServer; + r = User::LeaveIfError(fileServer.Connect()); + if (r != KErrNone) + return false; + fileServer.Close (); +#endif + + r = User::LoadPhysicalDevice(KPddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + + r = User::LoadLogicalDevice(KLddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + +#ifndef __WINS__ + r = StartC32(); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); +#endif + + return true; +} + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , errnum(KErrNone) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + // FIXME: Maybe need added check an ReadWrite open mode? + Q_UNUSED(mode) + + if (!loadDevices()) { + q_ptr->setError(QSerialPort::UnknownError); + return false; + } + + RCommServ server; + errnum = server.Connect(); + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (systemLocation.contains("BTCOMM")) + errnum = server.LoadCommModule(KBluetoothModuleName); + else if (systemLocation.contains("IRCOMM")) + errnum = server.LoadCommModule(KInfraRedModuleName); + else if (systemLocation.contains("ACM")) + errnum = server.LoadCommModule(KACMModuleName); + else + errnum = server.LoadCommModule(KRS232ModuleName); + + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + // In Symbian OS port opening only in R/W mode? + TPtrC portName(static_cast(systemLocation.utf16()), systemLocation.length()); + errnum = descriptor.Open(server, portName, ECommExclusive); + + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + // Save current port settings. + errnum = descriptor.Config(restoredSettings); + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + if (settingsRestoredOnClose) + descriptor.SetConfig(restoredSettings); + descriptor.Close(); +} + +QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const +{ + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + + TUint signalMask = 0; + descriptor.Signals(signalMask); + + if (signalMask & KSignalCTS) + ret |= QSerialPort::ClearToSendSignal; + if (signalMask & KSignalDSR) + ret |= QSerialPort::DataSetReadySignal; + if (signalMask & KSignalDCD) + ret |= QSerialPort::DataCarrierDetectSignal; + if (signalMask & KSignalRNG) + ret |= QSerialPort::RingIndicatorSignal; + if (signalMask & KSignalRTS) + ret |= QSerialPort::RequestToSendSignal; + if (signalMask & KSignalDTR) + ret |= QSerialPort::DataTerminalReadySignal; + + //if (signalMask & KSignalBreak) + // ret |= + return ret; +} + +bool QSerialPortPrivate::setDataTerminalReady(bool set) +{ + TInt r; + if (set) + r = descriptor.SetSignalsToMark(KSignalDTR); + else + r = descriptor.SetSignalsToSpace(KSignalDTR); + + return r == KErrNone; +} + +bool QSerialPortPrivate::setRequestToSend(bool set) +{ + TInt r; + if (set) + r = descriptor.SetSignalsToMark(KSignalRTS); + else + r = descriptor.SetSignalsToSpace(KSignalRTS); + + return r == KErrNone; +} + +bool QSerialPortPrivate::flush() +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + TUint flags = 0; + if (dir & QSerialPort::Input) + flags |= KCommResetRx; + if (dir & QSerialPort::Output) + flags |= KCommResetTx; + TInt r = descriptor.ResetBuffers(flags); + return r == KErrNone; +} + +bool QSerialPortPrivate::sendBreak(int duration) +{ + TRequestStatus status; + descriptor.Break(status, TTimeIntervalMicroSeconds32(duration * 1000)); + return false; +} + +bool QSerialPortPrivate::setBreakEnabled(bool set) +{ + // TODO: Implement me + return false; +} + +qint64 QSerialPortPrivate::systemInputQueueSize () const +{ + return descriptor.QueryReceiveBuffer(); +} + +qint64 QSerialPortPrivate::systemOutputQueueSize () const +{ + // TODO: Implement me + return 0; +} + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return readBuffer.size(); +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + // TODO: Implement me + return -1; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + // TODO: Implement me + return -1; +} + +bool QSerialPortPrivate::waitForReadyRead(int msec) +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msec) +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir) +{ + if (dir != QSerialPort::AllDirections) { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + + baudRate = settingFromBaudRate(baudRate); + if (baudRate) + currentSettings().iRate = static_cast(baudRate); + else { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) +{ + switch (dataBits) { + case QSerialPort::Data5: + currentSettings().iDataBits = EData5; + break; + case QSerialPort::Data6: + currentSettings().iDataBits = EData6; + break; + case QSerialPort::Data7: + currentSettings().iDataBits = EData7; + break; + case QSerialPort::Data8: + currentSettings().iDataBits = EData8; + break; + default: + currentSettings().iDataBits = EData8; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) +{ + switch (parity) { + case QSerialPort::NoParity: + currentSettings().iParity = EParityNone; + break; + case QSerialPort::EvenParity: + currentSettings().iParity = EParityEven; + break; + case QSerialPort::OddParity: + currentSettings().iParity = EParityOdd; + break; + case QSerialPort::MarkParity: + currentSettings().iParity = EParityMark; + break; + case QSerialPort::SpaceParity: + currentSettings().iParity = EParitySpace; + break; + default: + currentSettings().iParity = EParityNone; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) +{ + switch (stopBits) { + case QSerialPort::OneStop: + currentSettings().iStopBits = EStop1; + break; + case QSerialPort::TwoStop: + currentSettings().iStopBits = EStop2; + break; + default: + currentSettings().iStopBits = EStop1; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow) +{ + switch (flow) { + case QSerialPort::NoFlowControl: + currentSettings().iHandshake = KConfigFailDSR; + break; + case QSerialPort::HardwareControl: + currentSettings().iHandshake = KConfigObeyCTS | KConfigFreeRTS; + break; + case QSerialPort::SoftwareControl: + currentSettings().iHandshake = KConfigObeyXoff | KConfigSendXoff; + break; + default: + currentSettings().iHandshake = KConfigFailDSR; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::notifyRead() +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::notifyWrite() +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::updateCommConfig() +{ + if (descriptor.SetConfig(currentSettings) != KErrNone) { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + return true; +} + +void QSerialPortPrivate::detectDefaultSettings() +{ + // Detect baud rate. + inputBaudRate = baudRateFromSetting(currentSettings().iRate); + outputBaudRate = inputBaudRate; + + // Detect databits. + switch (currentSettings().iDataBits) { + case EData5: + dataBits = QSerialPort::Data5; + break; + case EData6: + dataBits = QSerialPort::Data6; + break; + case EData7: + dataBits = QSerialPort::Data7; + break; + case EData8: + dataBits = QSerialPort::Data8; + break; + default: + dataBits = QSerialPort::UnknownDataBits; + break; + } + + // Detect parity. + switch (currentSettings().iParity) { + case EParityNone: + parity = QSerialPort::NoParity; + break; + case EParityEven: + parity = QSerialPort::EvenParity; + break; + case EParityOdd: + parity = QSerialPort::OddParity; + break; + case EParityMark: + parity = QSerialPort::MarkParity; + break; + case EParitySpace: + parity = QSerialPort::SpaceParity; + break; + default: + parity = QSerialPort::UnknownParity; + break; + } + + // Detect stopbits. + switch (currentSettings().iStopBits) { + case EStop1: + stopBits = QSerialPort::OneStop; + break; + case EStop2: + stopBits = QSerialPort::TwoStop; + break; + default: + stopBits = QSerialPort::UnknownStopBits; + break; + } + + // Detect flow control. + if ((currentSettings().iHandshake & (KConfigObeyXoff | KConfigSendXoff)) + == (KConfigObeyXoff | KConfigSendXoff)) + flow = QSerialPort::SoftwareControl; + else if ((currentSettings().iHandshake & (KConfigObeyCTS | KConfigFreeRTS)) + == (KConfigObeyCTS | KConfigFreeRTS)) + flow = QSerialPort::HardwareControl; + else if (currentSettings().iHandshake & KConfigFailDSR) + flow = QSerialPort::NoFlowControl; + else + flow = QSerialPort::UnknownFlowControl; +} + +QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const +{ + QSerialPort::SerialPortError error; + switch (errnum) { + case KErrPermissionDenied: + error = QSerialPort::DeviceNotFoundError; + break; + case KErrLocked: + error = QSerialPort::PermissionError; + break; + case KErrAccessDenied: + error = QSerialPort::PermissionError; + break; + default: + error = QSerialPort::UnknownError; + break; + } + return error; +} + +bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + + // FIXME: I'm not sure in implementation this method. + // Someone needs to check and correct. + + TRequestStatus timerStatus; + TRequestStatus readStatus; + TRequestStatus writeStatus; + + if (msecs > 0) { + if (!selectTimer.Handle()) { + if (selectTimer.CreateLocal() != KErrNone) + return false; + } + selectTimer.HighRes(timerStatus, msecs * 1000); + } + + if (checkRead) + descriptor.NotifyDataAvailable(readStatus); + + if (checkWrite) + descriptor.NotifyOutputEmpty(writeStatus); + + enum { STATUSES_COUNT = 3 }; + TRequestStatus *statuses[STATUSES_COUNT]; + TInt num = 0; + statuses[num++] = &timerStatus; + statuses[num++] = &readStatus; + statuses[num++] = &writeStatus; + + User::WaitForNRequest(statuses, num); + + bool result = false; + + // By timeout? + if (timerStatus != KRequestPending) { + Q_ASSERT(selectForRead); + *selectForRead = false; + Q_ASSERT(selectForWrite); + *selectForWrite = false; + } else { + selectTimer.Cancel(); + User::WaitForRequest(timerStatus); + + // By read? + if (readStatus != KRequestPending) { + Q_ASSERT(selectForRead); + *selectForRead = true; + } + + // By write? + if (writeStatus != KRequestPending) { + Q_ASSERT(selectForWrite); + *selectForWrite = true; + } + + if (checkRead) + descriptor.NotifyDataAvailableCancel(); + if (checkWrite) + descriptor.NotifyOutputEmptyCancel(); + + result = true; + } + return result; +} + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + // Port name is equval to port systemLocation. + return port; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + // Port name is equval to port systemLocation. + return location; +} + +typedef QMap BaudRateMap; + +// This table contains correspondences standard pairs values of +// baud rates that are defined in files +// - d32comm.h for Symbian^3 +// - d32public.h for Symbian SR1 + +static const BaudRateMap createStandardBaudRateMap() +{ + BaudRateMap baudRateMap; + + baudRateMap.insert(50, EBps50) + baudRateMap.insert(75, EBps75) + baudRateMap.insert(110, EBps110) + baudRateMap.insert(134, EBps134) + baudRateMap.insert(150, EBps150) + baudRateMap.insert(300, EBps300) + baudRateMap.insert(600, EBps600) + baudRateMap.insert(1200, EBps1200) + baudRateMap.insert(1800, EBps1800) + baudRateMap.insert(2000, EBps2000) + baudRateMap.insert(2400, EBps2400) + baudRateMap.insert(3600, EBps3600) + baudRateMap.insert(4800, EBps4800) + baudRateMap.insert(7200, EBps7200) + baudRateMap.insert(9600, EBps9600) + baudRateMap.insert(19200, EBps19200) + baudRateMap.insert(38400, EBps38400) + baudRateMap.insert(57600, EBps57600) + baudRateMap.insert(115200, EBps115200) + baudRateMap.insert(230400, EBps230400) + baudRateMap.insert(460800, EBps460800) + baudRateMap.insert(576000, EBps576000) + baudRateMap.insert(921600, EBps921600) + baudRateMap.insert(1152000, EBps1152000) + // << baudRateMap.insert(1843200, EBps1843200) only for Symbian SR1 + baudRateMap.insert(4000000, EBps4000000); + + return baudRateMap; +} + +static const BaudRateMap& standardBaudRateMap() +{ + static const BaudRateMap baudRateMap = createStandardBaudRateMap(); + return baudRateMap; +} + +qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) +{ + return standardBaudRateMap().key(setting); +} + +qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) +{ + return standardBaudRateMap().value(baudRate); +} + +QList QSerialPortPrivate::standardBaudRates() +{ + return standardBaudRateMap().keys(); +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport_symbian_p.h b/libs/serialport/qserialport_symbian_p.h new file mode 100644 index 0000000000000000000000000000000000000000..7f9eaddd3eff92081ec11aef4815498623f76c89 --- /dev/null +++ b/libs/serialport/qserialport_symbian_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** 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$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_SYMBIAN_P_H +#define QSERIALPORT_SYMBIAN_P_H + +#include "qserialport_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QSerialPortPrivate : public QSerialPortPrivateData +{ +public: + QSerialPortPrivate(QSerialPort *q); + + bool open(QIODevice::OpenMode mode); + void close(); + + QSerialPort::PinoutSignals pinoutSignals() const; + + bool setDataTerminalReady(bool set); + bool setRequestToSend(bool set); + + bool flush(); + bool clear(QSerialPort::Directions dir); + + bool sendBreak(int duration); + bool setBreakEnabled(bool set); + + qint64 systemInputQueueSize () const; + qint64 systemOutputQueueSize () const; + + qint64 bytesAvailable() const; + + qint64 readFromBuffer(char *data, qint64 maxSize); + qint64 writeToBuffer(const char *data, qint64 maxSize); + + bool waitForReadyRead(int msec); + bool waitForBytesWritten(int msec); + + bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir); + 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 notifyRead(); + bool notifyWrite(); + + static QString portNameToSystemLocation(const QString &port); + static QString portNameFromSystemLocation(const QString &location); + + static qint32 baudRateFromSetting(qint32 setting); + static qint32 settingFromBaudRate(qint32 baudRate); + + static QList standardBaudRates(); + + TCommConfig currentSettings; + TCommConfig restoredSettings; + RComm descriptor; + mutable RTimer selectTimer; + TInt errnum; + +private: + bool updateCommConfig(); + + void detectDefaultSettings(); + QSerialPort::SerialPortError decodeSystemError() const; + + bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut); +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_SYMBIAN_P_H diff --git a/libs/serialport/qserialport_unix.cpp b/libs/serialport/qserialport_unix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f6c8ccbafa734f578db1aca5a6abfeedfbbb9a8 --- /dev/null +++ b/libs/serialport/qserialport_unix.cpp @@ -0,0 +1,1343 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_unix_p.h" +#include "qttylocker_unix_p.h" + +#include +#include +#include +#include +#include + +#ifdef Q_OS_MAC +#if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) +#include +#endif +#endif + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class ReadNotifier : public QSocketNotifier +{ +public: + ReadNotifier(QSerialPortPrivate *d, QObject *parent) + : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent) + , dptr(d) + {} + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + bool ret = QSocketNotifier::event(e); + if (ret) + dptr->readNotification(); + return ret; + } + +private: + QSerialPortPrivate *dptr; +}; + +class WriteNotifier : public QSocketNotifier +{ +public: + WriteNotifier(QSerialPortPrivate *d, QObject *parent) + : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent) + , dptr(d) + {} + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + bool ret = QSocketNotifier::event(e); + if (ret) + dptr->writeNotification(QSerialPortPrivateData::WriteChunkSize); + return ret; + } + +private: + QSerialPortPrivate *dptr; +}; + +class ExceptionNotifier : public QSocketNotifier +{ +public: + ExceptionNotifier(QSerialPortPrivate *d, QObject *parent) + : QSocketNotifier(d->descriptor, QSocketNotifier::Exception, parent) + , dptr(d) + {} + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + bool ret = QSocketNotifier::event(e); + if (ret) + dptr->exceptionNotification(); + return ret; + } + +private: + QSerialPortPrivate *dptr; +}; + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , descriptor(-1) + , isCustomBaudRateSupported(false) + , readNotifier(0) + , writeNotifier(0) + , exceptionNotifier(0) + , readPortNotifierCalled(false) + , readPortNotifierState(false) + , readPortNotifierStateSet(false) + , emittedReadyRead(false) + , emittedBytesWritten(false) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); + const char *ptr = portName.constData(); + + bool byCurrPid = false; + if (QTtyLocker::isLocked(ptr, &byCurrPid)) { + q_ptr->setError(QSerialPort::PermissionError); + return false; + } + + int flags = O_NOCTTY | O_NONBLOCK; + + switch (mode & QIODevice::ReadWrite) { + case QIODevice::WriteOnly: + flags |= O_WRONLY; + break; + case QIODevice::ReadWrite: + flags |= O_RDWR; + break; + default: + flags |= O_RDONLY; + break; + } + + descriptor = ::open(systemLocation.toLocal8Bit().constData(), flags); + + if (descriptor == -1) { + q_ptr->setError(decodeSystemError()); + return false; + } + + ::fcntl(descriptor, F_SETFL, FNDELAY); + + QTtyLocker::lock(ptr); + if (!QTtyLocker::isLocked(ptr, &byCurrPid)) { + q_ptr->setError(QSerialPort::PermissionError); + return false; + } + +#ifdef TIOCEXCL + ::ioctl(descriptor, TIOCEXCL); +#endif + + if (::tcgetattr(descriptor, &restoredTermios) == -1) { + q_ptr->setError(decodeSystemError()); + return false; + } + + currentTermios = restoredTermios; + ::cfmakeraw(¤tTermios); + currentTermios.c_cflag |= CLOCAL; + currentTermios.c_cc[VTIME] = 0; + currentTermios.c_cc[VMIN] = 0; + + if (mode & QIODevice::ReadOnly) + currentTermios.c_cflag |= CREAD; + + if (!updateTermios()) + return false; + + setExceptionNotificationEnabled(true); + + if ((flags & O_WRONLY) == 0) + setReadNotificationEnabled(true); + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + if (settingsRestoredOnClose) { + ::tcsetattr(descriptor, TCSANOW, &restoredTermios); +#ifdef Q_OS_LINUX + if (isCustomBaudRateSupported) + ::ioctl(descriptor, TIOCSSERIAL, &restoredSerialInfo); +#endif + } + +#ifdef TIOCNXCL + ::ioctl(descriptor, TIOCNXCL); +#endif + + if (readNotifier) { + readNotifier->setEnabled(false); + readNotifier->deleteLater(); + readNotifier = 0; + } + + if (writeNotifier) { + writeNotifier->setEnabled(false); + writeNotifier->deleteLater(); + writeNotifier = 0; + } + + if (exceptionNotifier) { + exceptionNotifier->setEnabled(false); + exceptionNotifier->deleteLater(); + exceptionNotifier = 0; + } + + ::close(descriptor); + + QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); + const char *ptr = portName.constData(); + + bool byCurrPid = false; + if (QTtyLocker::isLocked(ptr, &byCurrPid) && byCurrPid) + QTtyLocker::unlock(ptr); + + descriptor = -1; + isCustomBaudRateSupported = false; +} + +QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const +{ + int arg = 0; + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + + if (::ioctl(descriptor, TIOCMGET, &arg) == -1) { + q_ptr->setError(decodeSystemError()); + return ret; + } + +#ifdef TIOCM_LE + if (arg & TIOCM_LE) + ret |= QSerialPort::DataSetReadySignal; +#endif +#ifdef TIOCM_DTR + if (arg & TIOCM_DTR) + ret |= QSerialPort::DataTerminalReadySignal; +#endif +#ifdef TIOCM_RTS + if (arg & TIOCM_RTS) + ret |= QSerialPort::RequestToSendSignal; +#endif +#ifdef TIOCM_ST + if (arg & TIOCM_ST) + ret |= QSerialPort::SecondaryTransmittedDataSignal; +#endif +#ifdef TIOCM_SR + if (arg & TIOCM_SR) + ret |= QSerialPort::SecondaryReceivedDataSignal; +#endif +#ifdef TIOCM_CTS + if (arg & TIOCM_CTS) + ret |= QSerialPort::ClearToSendSignal; +#endif +#ifdef TIOCM_CAR + if (arg & TIOCM_CAR) + ret |= QSerialPort::DataCarrierDetectSignal; +#elif defined TIOCM_CD + if (arg & TIOCM_CD) + ret |= QSerialPort::DataCarrierDetectSignal; +#endif +#ifdef TIOCM_RNG + if (arg & TIOCM_RNG) + ret |= QSerialPort::RingIndicatorSignal; +#elif defined TIOCM_RI + if (arg & TIOCM_RI) + ret |= QSerialPort::RingIndicatorSignal; +#endif +#ifdef TIOCM_DSR + if (arg & TIOCM_DSR) + ret |= QSerialPort::DataSetReadySignal; +#endif + + return ret; +} + +bool QSerialPortPrivate::setDataTerminalReady(bool set) +{ + int status = TIOCM_DTR; + return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1; +} + +bool QSerialPortPrivate::setRequestToSend(bool set) +{ + int status = TIOCM_RTS; + return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1; +} + +bool QSerialPortPrivate::flush() +{ + return writeNotification() && (::tcdrain(descriptor) != -1); +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + return ::tcflush(descriptor, (dir == QSerialPort::AllDirections) + ? TCIOFLUSH : (dir & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) != -1; +} + +bool QSerialPortPrivate::sendBreak(int duration) +{ + return ::tcsendbreak(descriptor, duration) != -1; +} + +bool QSerialPortPrivate::setBreakEnabled(bool set) +{ + return ::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) != -1; +} + +qint64 QSerialPortPrivate::systemInputQueueSize () const +{ + int nbytes = 0; +#ifdef TIOCINQ + if (::ioctl(descriptor, TIOCINQ, &nbytes) == -1) + return -1; +#endif + return nbytes; +} + +qint64 QSerialPortPrivate::systemOutputQueueSize () const +{ + int nbytes = 0; +#ifdef TIOCOUTQ + if (::ioctl(descriptor, TIOCOUTQ, &nbytes) == -1) + return -1; +#endif + return nbytes; +} + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return readBuffer.size(); +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + if (readBuffer.isEmpty()) + return 0; + + if (maxSize == 1) { + *data = readBuffer.getChar(); + if (readBuffer.isEmpty()) + setReadNotificationEnabled(true); + return 1; + } + + const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize); + qint64 readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), + readBuffer.nextDataBlockSize()); + ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + } + + if (!isReadNotificationEnabled()) + setReadNotificationEnabled(true); + + if (readSoFar > 0) { + if (readBuffer.isEmpty()) + setReadNotificationEnabled(true); + return readSoFar; + } + + return readSoFar; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + char *ptr = writeBuffer.reserve(maxSize); + if (maxSize == 1) + *ptr = *data; + else + ::memcpy(ptr, data, maxSize); + + const qint64 written = maxSize; + + if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled()) + setWriteNotificationEnabled(true); + + return written; +} + +bool QSerialPortPrivate::waitForReadyRead(int msecs) +{ + QElapsedTimer stopWatch; + + stopWatch.start(); + + do { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), + timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (readyToRead) { + if (readNotification()) + return true; + } + + if (readyToWrite) + writeNotification(WriteChunkSize); + + } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msecs) +{ + if (writeBuffer.isEmpty()) + return false; + + QElapsedTimer stopWatch; + + stopWatch.start(); + + forever { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), + timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (readyToRead && !readNotification()) + return false; + + if (readyToWrite) + return writeNotification(WriteChunkSize); + } + return false; +} + +bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir) +{ + bool ret = baudRate > 0; + + // prepare section + + if (ret) { + const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate); + if (unixBaudRate > 0) { + // try prepate to set standard baud rate +#ifdef Q_OS_LINUX + // prepare to forcefully reset the custom mode + if (isCustomBaudRateSupported) { + //currentSerialInfo.flags |= ASYNC_SPD_MASK; + currentSerialInfo.flags &= ~(ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); + currentSerialInfo.custom_divisor = 0; + } +#endif + // prepare to set standard baud rate + ret = !(((dir & QSerialPort::Input) && ::cfsetispeed(¤tTermios, unixBaudRate) < 0) + || ((dir & QSerialPort::Output) && ::cfsetospeed(¤tTermios, unixBaudRate) < 0)); + } else { + // try prepate to set custom baud rate +#ifdef Q_OS_LINUX + // prepare to forcefully set the custom mode + if (isCustomBaudRateSupported) { + currentSerialInfo.flags &= ~ASYNC_SPD_MASK; + currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); + currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / baudRate; + if (currentSerialInfo.custom_divisor == 0) + currentSerialInfo.custom_divisor = 1; + // for custom mode needed prepare to set B38400 baud rate + ret = (::cfsetspeed(¤tTermios, B38400) != -1); + } else { + ret = false; + } +#elif defined(Q_OS_MAC) + +# if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) + // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates + // other than those specified by POSIX. The driver for the underlying serial hardware + // ultimately determines which baud rates can be used. This ioctl sets both the input + // and output speed. + ret = ::ioctl(descriptor, IOSSIOSPEED, &baudRate) != -1; +# else + // others MacOSX version, can't prepare to set custom baud rate + ret = false; +# endif + +#else + // others *nix OS, can't prepare to set custom baud rate + ret = false; +#endif + } + } + + // finally section + +#ifdef Q_OS_LINUX + if (ret && isCustomBaudRateSupported) // finally, set or reset the custom mode + ret = ::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) != -1; +#endif + + if (ret) // finally, set baud rate + ret = updateTermios(); + else + q_ptr->setError(decodeSystemError()); + return ret; +} + +bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) +{ + currentTermios.c_cflag &= ~CSIZE; + switch (dataBits) { + case QSerialPort::Data5: + currentTermios.c_cflag |= CS5; + break; + case QSerialPort::Data6: + currentTermios.c_cflag |= CS6; + break; + case QSerialPort::Data7: + currentTermios.c_cflag |= CS7; + break; + case QSerialPort::Data8: + currentTermios.c_cflag |= CS8; + break; + default: + currentTermios.c_cflag |= CS8; + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) +{ + currentTermios.c_iflag &= ~(PARMRK | INPCK); + currentTermios.c_iflag |= IGNPAR; + + switch (parity) { + +#ifdef CMSPAR + // Here Installation parity only for GNU/Linux where the macro CMSPAR. + case QSerialPort::SpaceParity: + currentTermios.c_cflag &= ~PARODD; + currentTermios.c_cflag |= PARENB | CMSPAR; + break; + case QSerialPort::MarkParity: + currentTermios.c_cflag |= PARENB | CMSPAR | PARODD; + break; +#endif + case QSerialPort::NoParity: + currentTermios.c_cflag &= ~PARENB; + break; + case QSerialPort::EvenParity: + currentTermios.c_cflag &= ~PARODD; + currentTermios.c_cflag |= PARENB; + break; + case QSerialPort::OddParity: + currentTermios.c_cflag |= PARENB | PARODD; + break; + default: + currentTermios.c_cflag |= PARENB; + currentTermios.c_iflag |= PARMRK | INPCK; + currentTermios.c_iflag &= ~IGNPAR; + break; + } + + return updateTermios(); +} + +bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) +{ + switch (stopBits) { + case QSerialPort::OneStop: + currentTermios.c_cflag &= ~CSTOPB; + break; + case QSerialPort::TwoStop: + currentTermios.c_cflag |= CSTOPB; + break; + default: + currentTermios.c_cflag &= ~CSTOPB; + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow) +{ + switch (flow) { + case QSerialPort::NoFlowControl: + currentTermios.c_cflag &= ~CRTSCTS; + currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY); + break; + case QSerialPort::HardwareControl: + currentTermios.c_cflag |= CRTSCTS; + currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY); + break; + case QSerialPort::SoftwareControl: + currentTermios.c_cflag &= ~CRTSCTS; + currentTermios.c_iflag |= IXON | IXOFF | IXANY; + break; + default: + currentTermios.c_cflag &= ~CRTSCTS; + currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY); + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) +{ + tcflag_t parmrkMask = PARMRK; +#ifndef CMSPAR + // in space/mark parity emulation also used PARMRK flag + if (parity == QSerialPort::SpaceParity + || parity == QSerialPort::MarkParity) { + parmrkMask = 0; + } +#endif //CMSPAR + switch (policy) { + case QSerialPort::SkipPolicy: + currentTermios.c_iflag &= ~parmrkMask; + currentTermios.c_iflag |= IGNPAR | INPCK; + break; + case QSerialPort::PassZeroPolicy: + currentTermios.c_iflag &= ~(IGNPAR | parmrkMask); + currentTermios.c_iflag |= INPCK; + break; + case QSerialPort::IgnorePolicy: + currentTermios.c_iflag &= ~INPCK; + break; + case QSerialPort::StopReceivingPolicy: + currentTermios.c_iflag &= ~IGNPAR; + currentTermios.c_iflag |= parmrkMask | INPCK; + break; + default: + currentTermios.c_iflag &= ~INPCK; + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::readNotification() +{ + // Prevent recursive calls + if (readPortNotifierCalled) { + if (!readPortNotifierStateSet) { + readPortNotifierStateSet = true; + readPortNotifierState = isReadNotificationEnabled(); + setReadNotificationEnabled(false); + } + } + + readPortNotifierCalled = true; + + // Always buffered, read data from the port into the read buffer + qint64 newBytes = readBuffer.size(); + qint64 bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1; + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the port. + return false; + } + } + + char *ptr = readBuffer.reserve(bytesToRead); + const qint64 readBytes = readFromPort(ptr, bytesToRead); + + if (readBytes <= 0) { + readBuffer.chop(bytesToRead); + return false; + } + + readBuffer.chop(bytesToRead - qMax(readBytes, qint64(0))); + + newBytes = readBuffer.size() - newBytes; + + // If read buffer is full, disable the read port notifier. + if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize) + setReadNotificationEnabled(false); + + // only emit readyRead() when not recursing, and only if there is data available + const bool hasData = newBytes > 0; + + if (!emittedReadyRead && hasData) { + emittedReadyRead = true; + emit q_ptr->readyRead(); + emittedReadyRead = false; + } + + if (!hasData) + setReadNotificationEnabled(true); + + // reset the read port notifier state if we reentered inside the + // readyRead() connected slot. + if (readPortNotifierStateSet + && readPortNotifierState != isReadNotificationEnabled()) { + setReadNotificationEnabled(readPortNotifierState); + readPortNotifierStateSet = false; + } + return true; +} + +bool QSerialPortPrivate::writeNotification(int maxSize) +{ + const int tmp = writeBuffer.size(); + + if (writeBuffer.isEmpty()) { + setWriteNotificationEnabled(false); + return false; + } + + int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize); + + const char *ptr = writeBuffer.readPointer(); + + // Attempt to write it chunk. + qint64 written = writeToPort(ptr, nextSize); + if (written < 0) + return false; + + // Remove what we wrote so far. + writeBuffer.free(written); + if (written > 0) { + // Don't emit bytesWritten() recursively. + if (!emittedBytesWritten) { + emittedBytesWritten = true; + emit q_ptr->bytesWritten(written); + emittedBytesWritten = false; + } + } + + if (writeBuffer.isEmpty()) + setWriteNotificationEnabled(false); + + return (writeBuffer.size() < tmp); +} + +bool QSerialPortPrivate::exceptionNotification() +{ + QSerialPort::SerialPortError error = decodeSystemError(); + q_ptr->setError(error); + + return true; +} + +bool QSerialPortPrivate::updateTermios() +{ + if (::tcsetattr(descriptor, TCSANOW, ¤tTermios) == -1) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +void QSerialPortPrivate::detectDefaultSettings() +{ + // Detect baud rate. + const speed_t inputUnixBaudRate = ::cfgetispeed(¤tTermios); + const speed_t outputUnixBaudRate = ::cfgetospeed(¤tTermios); + bool isCustomBaudRateCurrentSet = false; + +#ifdef Q_OS_LINUX + // try detect the ability to support custom baud rate + isCustomBaudRateSupported = ::ioctl(descriptor, TIOCGSERIAL, ¤tSerialInfo) != -1 + && ::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) != -1; + + if (isCustomBaudRateSupported) { + restoredSerialInfo = currentSerialInfo; + + // assume that the baud rate is a custom + isCustomBaudRateCurrentSet = inputUnixBaudRate == B38400 && outputUnixBaudRate == B38400; + + if (isCustomBaudRateCurrentSet) { + if ((currentSerialInfo.flags & ASYNC_SPD_CUST) + && currentSerialInfo.custom_divisor > 0) { + + // yes, speed is really custom + inputBaudRate = currentSerialInfo.baud_base / currentSerialInfo.custom_divisor; + outputBaudRate = inputBaudRate; + } else { + // no, we were wrong and the speed is a standard 38400 baud + isCustomBaudRateCurrentSet = false; + } + } + } +#else + // other *nix +#endif + if (!isCustomBaudRateSupported || !isCustomBaudRateCurrentSet) { + inputBaudRate = QSerialPortPrivate::baudRateFromSetting(inputUnixBaudRate); + outputBaudRate = QSerialPortPrivate::baudRateFromSetting(outputUnixBaudRate); + } + + // Detect databits. + switch (currentTermios.c_cflag & CSIZE) { + case CS5: + dataBits = QSerialPort::Data5; + break; + case CS6: + dataBits = QSerialPort::Data6; + break; + case CS7: + dataBits = QSerialPort::Data7; + break; + case CS8: + dataBits = QSerialPort::Data8; + break; + default: + dataBits = QSerialPort::UnknownDataBits; + break; + } + + // Detect parity. +#ifdef CMSPAR + if (currentTermios.c_cflag & CMSPAR) { + parity = currentTermios.c_cflag & PARODD ? + QSerialPort::MarkParity : QSerialPort::SpaceParity; + } else { +#endif + if (currentTermios.c_cflag & PARENB) { + parity = currentTermios.c_cflag & PARODD ? + QSerialPort::OddParity : QSerialPort::EvenParity; + } else { + parity = QSerialPort::NoParity; + } +#ifdef CMSPAR + } +#endif + + // Detect stopbits. + stopBits = currentTermios.c_cflag & CSTOPB ? + QSerialPort::TwoStop : QSerialPort::OneStop; + + // Detect flow control. + if ((!(currentTermios.c_cflag & CRTSCTS)) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY)))) + flow = QSerialPort::NoFlowControl; + else if ((!(currentTermios.c_cflag & CRTSCTS)) && (currentTermios.c_iflag & (IXON | IXOFF | IXANY))) + flow = QSerialPort::SoftwareControl; + else if ((currentTermios.c_cflag & CRTSCTS) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY)))) + flow = QSerialPort::HardwareControl; + else + flow = QSerialPort::UnknownFlowControl; +} + +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; +#ifdef Q_OS_MAC + case ENXIO: + error = QSerialPort::ResourceError; + break; +#endif + default: + error = QSerialPort::UnknownError; + break; + } + return error; +} + +bool QSerialPortPrivate::isReadNotificationEnabled() const +{ + return readNotifier && readNotifier->isEnabled(); +} + +void QSerialPortPrivate::setReadNotificationEnabled(bool enable) +{ + if (readNotifier) { + readNotifier->setEnabled(enable); + } else if (enable) { + readNotifier = new ReadNotifier(this, q_ptr); + readNotifier->setEnabled(true); + } +} + +bool QSerialPortPrivate::isWriteNotificationEnabled() const +{ + return writeNotifier && writeNotifier->isEnabled(); +} + +void QSerialPortPrivate::setWriteNotificationEnabled(bool enable) +{ + if (writeNotifier) { + writeNotifier->setEnabled(enable); + } else if (enable) { + writeNotifier = new WriteNotifier(this, q_ptr); + writeNotifier->setEnabled(true); + } +} + +bool QSerialPortPrivate::isExceptionNotificationEnabled() const +{ + return exceptionNotifier && exceptionNotifier->isEnabled(); +} + +void QSerialPortPrivate::setExceptionNotificationEnabled(bool enable) +{ + if (exceptionNotifier) { + exceptionNotifier->setEnabled(enable); + } else if (enable) { + exceptionNotifier = new ExceptionNotifier(this, q_ptr); + exceptionNotifier->setEnabled(true); + } +} + +bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + Q_ASSERT(selectForRead); + Q_ASSERT(selectForWrite); + Q_ASSERT(timedOut); + + fd_set fdread; + FD_ZERO(&fdread); + if (checkRead) + FD_SET(descriptor, &fdread); + + fd_set fdwrite; + FD_ZERO(&fdwrite); + if (checkWrite) + FD_SET(descriptor, &fdwrite); + + struct timeval tv; + tv.tv_sec = msecs / 1000; + tv.tv_usec = (msecs % 1000) * 1000; + + int ret = ::select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv); + if (ret < 0) + return false; + if (ret == 0) { + *timedOut = true; + return false; + } + + *selectForRead = FD_ISSET(descriptor, &fdread); + *selectForWrite = FD_ISSET(descriptor, &fdwrite); + + return ret; +} + +qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize) +{ + qint64 bytesRead = 0; +#if defined (CMSPAR) + if (parity == QSerialPort::NoParity + || policy != QSerialPort::StopReceivingPolicy) { +#else + if (parity != QSerialPort::MarkParity + && parity != QSerialPort::SpaceParity) { +#endif + bytesRead = ::read(descriptor, data, maxSize); + } else {// Perform parity emulation. + bytesRead = readPerChar(data, maxSize); + } + + if (bytesRead <= 0) { + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::ResourceError) + error = QSerialPort::ReadError; + q_ptr->setError(error); + } + + return bytesRead; +} + +qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize) +{ + qint64 bytesWritten = 0; +#if defined (CMSPAR) + bytesWritten = ::write(descriptor, data, maxSize); +#else + if (parity != QSerialPort::MarkParity + && parity != QSerialPort::SpaceParity) { + bytesWritten = ::write(descriptor, data, maxSize); + } else {// Perform parity emulation. + bytesWritten = writePerChar(data, maxSize); + } +#endif + + if (bytesWritten < 0) { + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::ResourceError) + error = QSerialPort::WriteError; + q_ptr->setError(error); + } + + return bytesWritten; +} + +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) +} + +#ifndef CMSPAR + +qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize) +{ + qint64 ret = 0; + quint8 const charMask = (0xFF >> (8 - dataBits)); + + while (ret < maxSize) { + + bool par = evenParity(*data & charMask); + // False if need EVEN, true if need ODD. + par ^= parity == QSerialPort::MarkParity; + if (par ^ (currentTermios.c_cflag & PARODD)) { // Need switch parity mode? + currentTermios.c_cflag ^= PARODD; + flush(); //force sending already buffered data, because updateTermios() cleares buffers + //todo: add receiving buffered data!!! + if (!updateTermios()) + break; + } + + int r = ::write(descriptor, data, 1); + if (r < 0) + return -1; + if (r > 0) { + data += r; + ret += r; + } + } + return ret; +} + +#endif //CMSPAR + +qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize) +{ + qint64 ret = 0; + quint8 const charMask = (0xFF >> (8 - dataBits)); + + // 0 - prefix not started, + // 1 - received 0xFF, + // 2 - received 0xFF and 0x00 + int prefix = 0; + while (ret < maxSize) { + + qint64 r = ::read(descriptor, data, 1); + if (r < 0) { + if (errno == EAGAIN) // It is ok for nonblocking mode. + break; + return -1; + } + if (r == 0) + break; + + bool par = true; + switch (prefix) { + case 2: // Previously received both 0377 and 0. + par = false; + prefix = 0; + break; + case 1: // Previously received 0377. + if (*data == '\0') { + ++prefix; + continue; + } + prefix = 0; + break; + default: + if (*data == '\377') { + prefix = 1; + continue; + } + break; + } + // Now: par contains parity ok or error, *data contains received character + par ^= evenParity(*data & charMask); //par contains parity bit value for EVEN mode + par ^= (currentTermios.c_cflag & PARODD); //par contains parity bit value for current mode + if (par ^ (parity == QSerialPort::SpaceParity)) { //if parity error + switch (policy) { + case QSerialPort::SkipPolicy: + continue; //ignore received character + case QSerialPort::StopReceivingPolicy: + if (parity != QSerialPort::NoParity) + q_ptr->setError(QSerialPort::ParityError); + else + q_ptr->setError(*data == '\0' ? + QSerialPort::BreakConditionError : QSerialPort::FramingError); + return ++ret; //abort receiving + break; + case QSerialPort::UnknownPolicy: + // Unknown error policy is used! Falling back to PassZeroPolicy + case QSerialPort::PassZeroPolicy: + *data = '\0'; //replace received character by zero + break; + case QSerialPort::IgnorePolicy: + break; //ignore error and pass received character + } + } + ++data; + ++ret; + } + return ret; +} + +#ifdef Q_OS_MAC +static const QLatin1String defaultFilePathPrefix("/dev/cu."); +static const QLatin1String unusedFilePathPrefix("/dev/tty."); +#else +static const QLatin1String defaultFilePathPrefix("/dev/"); +#endif + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + QString ret = port; + +#ifdef Q_OS_MAC + ret.remove(unusedFilePathPrefix); +#endif + + if (!ret.contains(defaultFilePathPrefix)) + ret.prepend(defaultFilePathPrefix); + return ret; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + QString ret = location; + +#ifdef Q_OS_MAC + ret.remove(unusedFilePathPrefix); +#endif + + ret.remove(defaultFilePathPrefix); + return ret; +} + +typedef QMap BaudRateMap; + +// The OS specific defines can be found in termios.h + +static const BaudRateMap createStandardBaudRateMap() +{ + BaudRateMap baudRateMap; + +#ifdef B50 + baudRateMap.insert(50, B50); +#endif + +#ifdef B75 + baudRateMap.insert(75, B75); +#endif + +#ifdef B110 + baudRateMap.insert(110, B110); +#endif + +#ifdef B134 + baudRateMap.insert(134, B134); +#endif + +#ifdef B150 + baudRateMap.insert(150, B150); +#endif + +#ifdef B200 + baudRateMap.insert(200, B200); +#endif + +#ifdef B300 + baudRateMap.insert(300, B300); +#endif + +#ifdef B600 + baudRateMap.insert(600, B600); +#endif + +#ifdef B1200 + baudRateMap.insert(1200, B1200); +#endif + +#ifdef B1800 + baudRateMap.insert(1800, B1800); +#endif + +#ifdef B2400 + baudRateMap.insert(2400, B2400); +#endif + +#ifdef B4800 + baudRateMap.insert(4800, B4800); +#endif + +#ifdef B9600 + baudRateMap.insert(9600, B9600); +#endif + +#ifdef B19200 + baudRateMap.insert(19200, B19200); +#endif + +#ifdef B38400 + baudRateMap.insert(38400, B38400); +#endif + +#ifdef B57600 + baudRateMap.insert(57600, B57600); +#endif + +#ifdef B115200 + baudRateMap.insert(115200, B115200); +#endif + +#ifdef B230400 + baudRateMap.insert(230400, B230400); +#endif + +#ifdef B460800 + baudRateMap.insert(460800, B460800); +#endif + +#ifdef B500000 + baudRateMap.insert(500000, B500000); +#endif + +#ifdef B576000 + baudRateMap.insert(576000, B576000); +#endif + +#ifdef B921600 + baudRateMap.insert(921600, B921600); +#endif + +#ifdef B1000000 + baudRateMap.insert(1000000, B1000000); +#endif + +#ifdef B1152000 + baudRateMap.insert(1152000, B1152000); +#endif + +#ifdef B1500000 + baudRateMap.insert(1500000, B1500000); +#endif + +#ifdef B2000000 + baudRateMap.insert(2000000, B2000000); +#endif + +#ifdef B2500000 + baudRateMap.insert(2500000, B2500000); +#endif + +#ifdef B3000000 + baudRateMap.insert(3000000, B3000000); +#endif + +#ifdef B3500000 + baudRateMap.insert(3500000, B3500000); +#endif + +#ifdef B4000000 + baudRateMap.insert(4000000, B4000000); +#endif + + return baudRateMap; +} + +static const BaudRateMap& standardBaudRateMap() +{ + static const BaudRateMap baudRateMap = createStandardBaudRateMap(); + return baudRateMap; +} + +qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) +{ + return standardBaudRateMap().key(setting); +} + +qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) +{ + return standardBaudRateMap().value(baudRate); +} + +QList QSerialPortPrivate::standardBaudRates() +{ + return standardBaudRateMap().keys(); +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport_unix_p.h b/libs/serialport/qserialport_unix_p.h new file mode 100644 index 0000000000000000000000000000000000000000..ce70c243b3c546e8699cd15b0c93a6c199eff05c --- /dev/null +++ b/libs/serialport/qserialport_unix_p.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_UNIX_P_H +#define QSERIALPORT_UNIX_P_H + +#include "qserialport_p.h" + +#include +#include +#ifdef Q_OS_LINUX +# include +#endif + +QT_BEGIN_NAMESPACE + +class QSocketNotifier; + +class QSerialPortPrivate : public QSerialPortPrivateData +{ +public: + QSerialPortPrivate(QSerialPort *q); + + bool open(QIODevice::OpenMode mode); + void close(); + + QSerialPort::PinoutSignals pinoutSignals() const; + + bool setDataTerminalReady(bool set); + bool setRequestToSend(bool set); + + bool flush(); + bool clear(QSerialPort::Directions dir); + + bool sendBreak(int duration); + bool setBreakEnabled(bool set); + + qint64 systemInputQueueSize () const; + qint64 systemOutputQueueSize () const; + + qint64 bytesAvailable() const; + + qint64 readFromBuffer(char *data, qint64 maxSize); + qint64 writeToBuffer(const char *data, qint64 maxSize); + + bool waitForReadyRead(int msecs); + bool waitForBytesWritten(int msecs); + + bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir); + bool setDataBits(QSerialPort::DataBits dataBits); + bool setParity(QSerialPort::Parity parity); + bool setStopBits(QSerialPort::StopBits stopBits); + bool setFlowControl(QSerialPort::FlowControl flow); + bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + + bool readNotification(); + bool writeNotification(int maxSize = INT_MAX); + bool exceptionNotification(); + + static QString portNameToSystemLocation(const QString &port); + static QString portNameFromSystemLocation(const QString &location); + + static qint32 baudRateFromSetting(qint32 setting); + static qint32 settingFromBaudRate(qint32 baudRate); + + static QList standardBaudRates(); + + struct termios currentTermios; + struct termios restoredTermios; +#ifdef Q_OS_LINUX + struct serial_struct currentSerialInfo; + struct serial_struct restoredSerialInfo; +#endif + int descriptor; + bool isCustomBaudRateSupported; + + QSocketNotifier *readNotifier; + QSocketNotifier *writeNotifier; + QSocketNotifier *exceptionNotifier; + + bool readPortNotifierCalled; + bool readPortNotifierState; + bool readPortNotifierStateSet; + + bool emittedReadyRead; + bool emittedBytesWritten; + +private: + bool updateTermios(); + + void detectDefaultSettings(); + QSerialPort::SerialPortError decodeSystemError() const; + + bool isReadNotificationEnabled() const; + void setReadNotificationEnabled(bool enable); + bool isWriteNotificationEnabled() const; + void setWriteNotificationEnabled(bool enable); + bool isExceptionNotificationEnabled() const; + void setExceptionNotificationEnabled(bool enable); + + bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut); + + qint64 readFromPort(char *data, qint64 maxSize); + qint64 writeToPort(const char *data, qint64 maxSize); + +#ifndef CMSPAR + qint64 writePerChar(const char *data, qint64 maxSize); +#endif + qint64 readPerChar(char *data, qint64 maxSize); + +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_UNIX_P_H diff --git a/libs/serialport/qserialport_win.cpp b/libs/serialport/qserialport_win.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8d4d62adb62dba18b79209eb1ea55ff0af14677 --- /dev/null +++ b/libs/serialport/qserialport_win.cpp @@ -0,0 +1,1091 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_win_p.h" + +#ifndef Q_OS_WINCE +#include +#include +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else +#include "qt4support/qwineventnotifier_p.h" +#endif + +#ifndef CTL_CODE +# define CTL_CODE(DeviceType, Function, Method, Access) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ + ) +#endif + +#ifndef FILE_DEVICE_SERIAL_PORT +# define FILE_DEVICE_SERIAL_PORT 27 +#endif + +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif + +#ifndef FILE_ANY_ACCESS +# define FILE_ANY_ACCESS 0x00000000 +#endif + +#ifndef IOCTL_SERIAL_GET_DTRRTS +# define IOCTL_SERIAL_GET_DTRRTS \ + CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + +#ifndef SERIAL_DTR_STATE +# define SERIAL_DTR_STATE 0x00000001 +#endif + +#ifndef SERIAL_RTS_STATE +# define SERIAL_RTS_STATE 0x00000002 +#endif + +QT_BEGIN_NAMESPACE + +#ifndef Q_OS_WINCE + +class AbstractOverlappedEventNotifier : public QWinEventNotifier +{ +public: + enum Type { CommEvent, ReadCompletionEvent, WriteCompletionEvent }; + + AbstractOverlappedEventNotifier(QSerialPortPrivate *d, Type type, bool manual, QObject *parent) + : QWinEventNotifier(parent), dptr(d), t(type) { + ::memset(&o, 0, sizeof(o)); + o.hEvent = ::CreateEvent(NULL, manual, FALSE, NULL); + setHandle(o.hEvent); + dptr->notifiers[o.hEvent] = this; + } + + virtual bool processCompletionRoutine() = 0; + + virtual ~AbstractOverlappedEventNotifier() { + setEnabled(false); + ::CancelIo(o.hEvent); + ::CloseHandle(o.hEvent); + } + + Type type() const { return t; } + OVERLAPPED *overlappedPointer() { return &o; } + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + const bool ret = QWinEventNotifier::event(e); + processCompletionRoutine(); + return ret; + } + + QSerialPortPrivate *dptr; + Type t; + OVERLAPPED o; +}; + +class CommOverlappedEventNotifier : public AbstractOverlappedEventNotifier +{ +public: + CommOverlappedEventNotifier(QSerialPortPrivate *d, DWORD eventMask, QObject *parent) + : AbstractOverlappedEventNotifier(d, CommEvent, false, parent) + , originalEventMask(eventMask), triggeredEventMask(0) { + ::SetCommMask(dptr->descriptor, originalEventMask); + startWaitCommEvent(); + } + + void startWaitCommEvent() { ::WaitCommEvent(dptr->descriptor, &triggeredEventMask, &o); } + + bool processCompletionRoutine() Q_DECL_OVERRIDE { + DWORD numberOfBytesTransferred = 0; + ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); + + bool error = false; + + // Check for unexpected event. This event triggered when pulled previously + // opened device from the system, when opened as for not to read and not to + // write options and so forth. + if (triggeredEventMask == 0) + error = true; + + // Workaround for standard CDC ACM serial ports, for which triggered an + // unexpected event EV_TXEMPTY at data transmission. + if ((originalEventMask & triggeredEventMask) == 0) { + if ((triggeredEventMask & EV_TXEMPTY) == 0) + error = true; + } + + // Start processing a caught error. + if (error || (EV_ERR & triggeredEventMask)) + dptr->processIoErrors(error); + + if (!error) + dptr->startAsyncRead(); + + return !error; + } + +private: + DWORD originalEventMask; + DWORD triggeredEventMask; +}; + +class ReadOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier +{ +public: + ReadOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent) + : AbstractOverlappedEventNotifier(d, ReadCompletionEvent, false, parent) {} + + bool processCompletionRoutine() Q_DECL_OVERRIDE { + DWORD numberOfBytesTransferred = 0; + ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); + bool ret = dptr->completeAsyncRead(numberOfBytesTransferred); + + // start async read for possible remainder into driver queue + if (ret && (numberOfBytesTransferred > 0) && (dptr->policy == QSerialPort::IgnorePolicy)) { + dptr->startAsyncRead(); + } else { // driver queue is emplty, so startup wait comm event + CommOverlappedEventNotifier *n = + reinterpret_cast(dptr->lookupCommEventNotifier()); + if (n) + n->startWaitCommEvent(); + } + + return ret; + } +}; + +class WriteOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier +{ +public: + WriteOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent) + : AbstractOverlappedEventNotifier(d, WriteCompletionEvent, false, parent) {} + + bool processCompletionRoutine() Q_DECL_OVERRIDE { + setEnabled(false); + DWORD numberOfBytesTransferred = 0; + ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); + return dptr->completeAsyncWrite(numberOfBytesTransferred); + } +}; + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , descriptor(INVALID_HANDLE_VALUE) + , parityErrorOccurred(false) + , actualReadBufferSize(0) + , actualWriteBufferSize(0) + , acyncWritePosition(0) + , readyReadEmitted(0) + , writeSequenceStarted(false) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD originalEventMask = EV_ERR; + + if (mode & QIODevice::ReadOnly) { + desiredAccess |= GENERIC_READ; + originalEventMask |= EV_RXCHAR; + } + if (mode & QIODevice::WriteOnly) + desiredAccess |= GENERIC_WRITE; + + descriptor = ::CreateFile(reinterpret_cast(systemLocation.utf16()), + desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (!::GetCommState(descriptor, &restoredDcb)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + currentDcb = restoredDcb; + currentDcb.fBinary = TRUE; + currentDcb.fInX = FALSE; + currentDcb.fOutX = FALSE; + currentDcb.fAbortOnError = FALSE; + currentDcb.fNull = FALSE; + currentDcb.fErrorChar = FALSE; + + if (!updateDcb()) + return false; + + if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + ::memset(¤tCommTimeouts, 0, sizeof(currentCommTimeouts)); + currentCommTimeouts.ReadIntervalTimeout = MAXDWORD; + + if (!updateCommTimeouts()) + return false; + + if (originalEventMask & EV_RXCHAR) { + QWinEventNotifier *n = new ReadOverlappedCompletionNotifier(this, q_ptr); + n->setEnabled(true); + } + + QWinEventNotifier *n = new CommOverlappedEventNotifier(this, originalEventMask, q_ptr); + n->setEnabled(true); + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + ::CancelIo(descriptor); + + qDeleteAll(notifiers); + notifiers.clear(); + + readBuffer.clear(); + actualReadBufferSize = 0; + + writeSequenceStarted = false; + writeBuffer.clear(); + actualWriteBufferSize = 0; + acyncWritePosition = 0; + + readyReadEmitted = false; + parityErrorOccurred = false; + + if (settingsRestoredOnClose) { + ::SetCommState(descriptor, &restoredDcb); + ::SetCommTimeouts(descriptor, &restoredCommTimeouts); + } + + ::CloseHandle(descriptor); + descriptor = INVALID_HANDLE_VALUE; +} + +#endif // #ifndef Q_OS_WINCE + +QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const +{ + DWORD modemStat = 0; + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + + if (!::GetCommModemStatus(descriptor, &modemStat)) { + q_ptr->setError(decodeSystemError()); + return ret; + } + + if (modemStat & MS_CTS_ON) + ret |= QSerialPort::ClearToSendSignal; + if (modemStat & MS_DSR_ON) + ret |= QSerialPort::DataSetReadySignal; + if (modemStat & MS_RING_ON) + ret |= QSerialPort::RingIndicatorSignal; + if (modemStat & MS_RLSD_ON) + ret |= QSerialPort::DataCarrierDetectSignal; + + DWORD bytesReturned = 0; + if (::DeviceIoControl(descriptor, IOCTL_SERIAL_GET_DTRRTS, NULL, 0, + &modemStat, sizeof(modemStat), + &bytesReturned, NULL)) { + + if (modemStat & SERIAL_DTR_STATE) + ret |= QSerialPort::DataTerminalReadySignal; + if (modemStat & SERIAL_RTS_STATE) + ret |= QSerialPort::RequestToSendSignal; + } + + return ret; +} + +bool QSerialPortPrivate::setDataTerminalReady(bool set) +{ + return ::EscapeCommFunction(descriptor, set ? SETDTR : CLRDTR); +} + +bool QSerialPortPrivate::setRequestToSend(bool set) +{ + return ::EscapeCommFunction(descriptor, set ? SETRTS : CLRRTS); +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::flush() +{ + return startAsyncWrite() && ::FlushFileBuffers(descriptor); +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + DWORD flags = 0; + if (dir & QSerialPort::Input) { + flags |= PURGE_RXABORT | PURGE_RXCLEAR; + actualReadBufferSize = 0; + } + if (dir & QSerialPort::Output) { + flags |= PURGE_TXABORT | PURGE_TXCLEAR; + actualWriteBufferSize = 0; + acyncWritePosition = 0; + writeSequenceStarted = false; + } + return ::PurgeComm(descriptor, flags); +} + +#endif + +bool QSerialPortPrivate::sendBreak(int duration) +{ + // FIXME: + if (setBreakEnabled(true)) { + ::Sleep(duration); + if (setBreakEnabled(false)) + return true; + } + return false; +} + +bool QSerialPortPrivate::setBreakEnabled(bool set) +{ + if (set) + return ::SetCommBreak(descriptor); + return ::ClearCommBreak(descriptor); +} + +qint64 QSerialPortPrivate::systemInputQueueSize () const +{ + COMSTAT cs; + ::memset(&cs, 0, sizeof(cs)); + if (!::ClearCommError(descriptor, NULL, &cs)) + return -1; + return cs.cbInQue; +} + +qint64 QSerialPortPrivate::systemOutputQueueSize () const +{ + COMSTAT cs; + ::memset(&cs, 0, sizeof(cs)); + if (!::ClearCommError(descriptor, NULL, &cs)) + return -1; + return cs.cbOutQue; +} + +#ifndef Q_OS_WINCE + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return actualReadBufferSize; +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + if (actualReadBufferSize == 0) + return 0; + + qint64 readSoFar = -1; + if (maxSize == 1 && actualReadBufferSize > 0) { + *data = readBuffer.getChar(); + actualReadBufferSize--; + readSoFar = 1; + } else { + const qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxSize); + readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + const int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, + qint64(readBuffer.nextDataBlockSize())); + ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + actualReadBufferSize -= bytesToReadFromThisBlock; + } + } + + return readSoFar; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + char *ptr = writeBuffer.reserve(maxSize); + if (maxSize == 1) { + *ptr = *data; + actualWriteBufferSize++; + } else { + ::memcpy(ptr, data, maxSize); + actualWriteBufferSize += maxSize; + } + + if (!writeSequenceStarted) + startAsyncWrite(WriteChunkSize); + + return maxSize; +} + +bool QSerialPortPrivate::waitForReadyRead(int msecs) +{ + QElapsedTimer stopWatch; + stopWatch.start(); + + do { + bool timedOut = false; + AbstractOverlappedEventNotifier *n = 0; + + if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) { + // This is occur timeout or another error + q_ptr->setError(decodeSystemError()); + return false; + } + + switch (n->type()) { + case AbstractOverlappedEventNotifier::CommEvent: + if (!n->processCompletionRoutine()) + return false; + break; + case AbstractOverlappedEventNotifier::ReadCompletionEvent: + return n->processCompletionRoutine(); + case AbstractOverlappedEventNotifier::WriteCompletionEvent: + n->processCompletionRoutine(); + break; + default: // newer called + return false; + } + } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); + + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msecs) +{ + if (writeBuffer.isEmpty()) + return false; + + QElapsedTimer stopWatch; + stopWatch.start(); + + forever { + bool timedOut = false; + AbstractOverlappedEventNotifier *n = 0; + + if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) { + q_ptr->setError(decodeSystemError()); + return false; + } + + switch (n->type()) { + case AbstractOverlappedEventNotifier::CommEvent: + // do nothing, jump to ReadCompletionEvent case + case AbstractOverlappedEventNotifier::ReadCompletionEvent: + n->processCompletionRoutine(); + break; + case AbstractOverlappedEventNotifier::WriteCompletionEvent: + return n->processCompletionRoutine(); + default: // newer called + return false; + } + } + + return false; +} + +#endif // #ifndef Q_OS_WINCE + +bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir) +{ + if (dir != QSerialPort::AllDirections) { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + currentDcb.BaudRate = baudRate; + return updateDcb(); +} + +bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) +{ + currentDcb.ByteSize = dataBits; + return updateDcb(); +} + +bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) +{ + currentDcb.fParity = TRUE; + switch (parity) { + case QSerialPort::NoParity: + currentDcb.Parity = NOPARITY; + currentDcb.fParity = FALSE; + break; + case QSerialPort::OddParity: + currentDcb.Parity = ODDPARITY; + break; + case QSerialPort::EvenParity: + currentDcb.Parity = EVENPARITY; + break; + case QSerialPort::MarkParity: + currentDcb.Parity = MARKPARITY; + break; + case QSerialPort::SpaceParity: + currentDcb.Parity = SPACEPARITY; + break; + default: + currentDcb.Parity = NOPARITY; + currentDcb.fParity = FALSE; + break; + } + return updateDcb(); +} + +bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) +{ + switch (stopBits) { + case QSerialPort::OneStop: + currentDcb.StopBits = ONESTOPBIT; + break; + case QSerialPort::OneAndHalfStop: + currentDcb.StopBits = ONE5STOPBITS; + break; + case QSerialPort::TwoStop: + currentDcb.StopBits = TWOSTOPBITS; + break; + default: + currentDcb.StopBits = ONESTOPBIT; + break; + } + return updateDcb(); +} + +bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow) +{ + currentDcb.fInX = FALSE; + currentDcb.fOutX = FALSE; + currentDcb.fOutxCtsFlow = FALSE; + currentDcb.fRtsControl = RTS_CONTROL_DISABLE; + switch (flow) { + case QSerialPort::NoFlowControl: + break; + case QSerialPort::SoftwareControl: + currentDcb.fInX = TRUE; + currentDcb.fOutX = TRUE; + break; + case QSerialPort::HardwareControl: + currentDcb.fOutxCtsFlow = TRUE; + currentDcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + break; + default: + break; + } + return updateDcb(); +} + +bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) +{ + policy = policy; + return true; +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::startAsyncRead() +{ + DWORD bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1; + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the port. + return false; + } + } + + AbstractOverlappedEventNotifier *n = lookupReadCompletionNotifier(); + if (!n) { + q_ptr->setError(QSerialPort::ResourceError); + return false; + } + + char *ptr = readBuffer.reserve(bytesToRead); + + if (::ReadFile(descriptor, ptr, bytesToRead, NULL, n->overlappedPointer())) + return true; + + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + if (error != QSerialPort::ResourceError) + error = QSerialPort::ReadError; + q_ptr->setError(error); + + readBuffer.truncate(actualReadBufferSize); + return false; + } + + return true; +} + +bool QSerialPortPrivate::startAsyncWrite(int maxSize) +{ + qint64 nextSize = 0; + const char *ptr = writeBuffer.readPointerAtPosition(acyncWritePosition, nextSize); + + nextSize = qMin(nextSize, qint64(maxSize)); + acyncWritePosition += nextSize; + + // no more data to write + if (!ptr || nextSize == 0) + return true; + + writeSequenceStarted = true; + + AbstractOverlappedEventNotifier *n = lookupFreeWriteCompletionNotifier(); + if (!n) { + q_ptr->setError(QSerialPort::ResourceError); + return false; + } + + n->setEnabled(true); + + if (::WriteFile(descriptor, ptr, nextSize, NULL, n->overlappedPointer())) + return true; + + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + writeSequenceStarted = false; + + if (error != QSerialPort::ResourceError) + error = QSerialPort::WriteError; + + q_ptr->setError(error); + return false; + } + + return true; +} + +#endif // #ifndef Q_OS_WINCE + +bool QSerialPortPrivate::processIoErrors(bool error) +{ + if (error) { + q_ptr->setError(QSerialPort::ResourceError); + return true; + } + + DWORD errors = 0; + const bool ret = ::ClearCommError(descriptor, &errors, NULL); + if (ret && errors) { + if (errors & CE_FRAME) { + q_ptr->setError(QSerialPort::FramingError); + } else if (errors & CE_RXPARITY) { + q_ptr->setError(QSerialPort::ParityError); + parityErrorOccurred = true; + } else if (errors & CE_BREAK) { + q_ptr->setError(QSerialPort::BreakConditionError); + } else { + q_ptr->setError(QSerialPort::UnknownError); + } + } + return ret; +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::completeAsyncRead(DWORD numberOfBytes) +{ + actualReadBufferSize += qint64(numberOfBytes); + readBuffer.truncate(actualReadBufferSize); + + if (numberOfBytes > 0) { + + // Process emulate policy. + if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) { + + parityErrorOccurred = false; + + // Ignore received character, remove it from buffer + if (policy == QSerialPort::SkipPolicy) { + readBuffer.getChar(); + // Force returning without emitting a readyRead() signal + return true; + } + + // Abort receiving + if (policy == QSerialPort::StopReceivingPolicy) { + readyReadEmitted = true; + emit q_ptr->readyRead(); + return true; + } + + // Replace received character by zero + if (policy == QSerialPort::PassZeroPolicy) { + readBuffer.getChar(); + readBuffer.putChar('\0'); + } + + } + + readyReadEmitted = true; + emit q_ptr->readyRead(); + } + return true; +} + +bool QSerialPortPrivate::completeAsyncWrite(DWORD numberOfBytes) +{ + writeBuffer.free(numberOfBytes); + actualWriteBufferSize -= qint64(numberOfBytes); + acyncWritePosition -= qint64(numberOfBytes); + + if (numberOfBytes > 0) + emit q_ptr->bytesWritten(numberOfBytes); + + if (writeBuffer.isEmpty()) + writeSequenceStarted = false; + else + startAsyncWrite(WriteChunkSize); + + return true; +} + +AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupFreeWriteCompletionNotifier() +{ + // find first free not running write notifier + foreach (AbstractOverlappedEventNotifier *n, notifiers) { + if ((n->type() == AbstractOverlappedEventNotifier::WriteCompletionEvent) + && !n->isEnabled()) { + return n; + } + } + // if all write notifiers in use, then create new write notifier + return new WriteOverlappedCompletionNotifier(this, q_ptr); +} + +AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupCommEventNotifier() +{ + foreach (AbstractOverlappedEventNotifier *n, notifiers) { + if (n->type() == AbstractOverlappedEventNotifier::CommEvent) + return n; + } + return 0; +} + +AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupReadCompletionNotifier() +{ + foreach (AbstractOverlappedEventNotifier *n, notifiers) { + if (n->type() == AbstractOverlappedEventNotifier::ReadCompletionEvent) + return n; + } + return 0; +} + +bool QSerialPortPrivate::updateDcb() +{ + if (!::SetCommState(descriptor, ¤tDcb)) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +bool QSerialPortPrivate::updateCommTimeouts() +{ + if (!::SetCommTimeouts(descriptor, ¤tCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +#endif // #ifndef Q_OS_WINCE + +void QSerialPortPrivate::detectDefaultSettings() +{ + // Detect baud rate. + inputBaudRate = quint32(currentDcb.BaudRate); + outputBaudRate = inputBaudRate; + + // Detect databits. + switch (currentDcb.ByteSize) { + case 5: + dataBits = QSerialPort::Data5; + break; + case 6: + dataBits = QSerialPort::Data6; + break; + case 7: + dataBits = QSerialPort::Data7; + break; + case 8: + dataBits = QSerialPort::Data8; + break; + default: + dataBits = QSerialPort::UnknownDataBits; + break; + } + + // Detect parity. + if ((currentDcb.Parity == NOPARITY) && !currentDcb.fParity) + parity = QSerialPort::NoParity; + else if ((currentDcb.Parity == SPACEPARITY) && currentDcb.fParity) + parity = QSerialPort::SpaceParity; + else if ((currentDcb.Parity == MARKPARITY) && currentDcb.fParity) + parity = QSerialPort::MarkParity; + else if ((currentDcb.Parity == EVENPARITY) && currentDcb.fParity) + parity = QSerialPort::EvenParity; + else if ((currentDcb.Parity == ODDPARITY) && currentDcb.fParity) + parity = QSerialPort::OddParity; + else + parity = QSerialPort::UnknownParity; + + // Detect stopbits. + switch (currentDcb.StopBits) { + case ONESTOPBIT: + stopBits = QSerialPort::OneStop; + break; + case ONE5STOPBITS: + stopBits = QSerialPort::OneAndHalfStop; + break; + case TWOSTOPBITS: + stopBits = QSerialPort::TwoStop; + break; + default: + stopBits = QSerialPort::UnknownStopBits; + break; + } + + // Detect flow control. + if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE) + && !currentDcb.fInX && !currentDcb.fOutX) { + flow = QSerialPort::NoFlowControl; + } else if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE) + && currentDcb.fInX && currentDcb.fOutX) { + flow = QSerialPort::SoftwareControl; + } else if (currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_HANDSHAKE) + && !currentDcb.fInX && !currentDcb.fOutX) { + flow = QSerialPort::HardwareControl; + } else + flow = QSerialPort::UnknownFlowControl; +} + +QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const +{ + QSerialPort::SerialPortError error; + switch (::GetLastError()) { + case ERROR_IO_PENDING: + error = QSerialPort::NoError; + break; + case ERROR_MORE_DATA: + error = QSerialPort::NoError; + break; + case ERROR_FILE_NOT_FOUND: + error = QSerialPort::DeviceNotFoundError; + break; + case ERROR_ACCESS_DENIED: + error = QSerialPort::PermissionError; + break; + case ERROR_INVALID_HANDLE: + error = QSerialPort::ResourceError; + break; + case ERROR_INVALID_PARAMETER: + error = QSerialPort::UnsupportedOperationError; + break; + case ERROR_BAD_COMMAND: + error = QSerialPort::ResourceError; + break; + case ERROR_DEVICE_REMOVED: + error = QSerialPort::ResourceError; + break; + default: + error = QSerialPort::UnknownError; + break; + } + return error; +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::waitAnyEvent(int msecs, bool *timedOut, + AbstractOverlappedEventNotifier **triggeredNotifier) +{ + Q_ASSERT(timedOut); + + QVector handles = notifiers.keys().toVector(); + DWORD waitResult = ::WaitForMultipleObjects(handles.count(), + handles.constData(), + FALSE, // wait any event + qMax(msecs, 0)); + if (waitResult == WAIT_TIMEOUT) { + *timedOut = true; + return false; + } + + if (int(waitResult) > (handles.count() - 1)) + return false; + + HANDLE h = handles.at(waitResult - WAIT_OBJECT_0); + *triggeredNotifier = notifiers.value(h); + return true; +} + +static const QLatin1String defaultPathPrefix("\\\\.\\"); + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + QString ret = port; + if (!ret.contains(defaultPathPrefix)) + ret.prepend(defaultPathPrefix); + return ret; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + QString ret = location; + if (ret.contains(defaultPathPrefix)) + ret.remove(defaultPathPrefix); + return ret; +} + +#endif // #ifndef Q_OS_WINCE + +// This table contains standard values of baud rates that +// are defined in MSDN and/or in Win SDK file winbase.h + +static const QList standardBaudRatePairList() +{ + + static const QList standardBaudRatesTable = QList() + + #ifdef CBR_110 + << CBR_110 + #endif + + #ifdef CBR_300 + << CBR_300 + #endif + + #ifdef CBR_600 + << CBR_600 + #endif + + #ifdef CBR_1200 + << CBR_1200 + #endif + + #ifdef CBR_2400 + << CBR_2400 + #endif + + #ifdef CBR_4800 + << CBR_4800 + #endif + + #ifdef CBR_9600 + << CBR_9600 + #endif + + #ifdef CBR_14400 + << CBR_14400 + #endif + + #ifdef CBR_19200 + << CBR_19200 + #endif + + #ifdef CBR_38400 + << CBR_38400 + #endif + + #ifdef CBR_56000 + << CBR_56000 + #endif + + #ifdef CBR_57600 + << CBR_57600 + #endif + + #ifdef CBR_115200 + << CBR_115200 + #endif + + #ifdef CBR_128000 + << CBR_128000 + #endif + + #ifdef CBR_256000 + << CBR_256000 + #endif + ; + + return standardBaudRatesTable; +}; + +qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) +{ + const QList baudRatePairs = standardBaudRatePairList(); + const QList::const_iterator baudRatePairListConstIterator = qFind(baudRatePairs, setting); + + return (baudRatePairListConstIterator != baudRatePairs.constEnd()) ? *baudRatePairListConstIterator : 0; +} + +qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) +{ + const QList baudRatePairList = standardBaudRatePairList(); + const QList::const_iterator baudRatePairListConstIterator = qFind(baudRatePairList, baudRate); + + return (baudRatePairListConstIterator != baudRatePairList.constEnd()) ? *baudRatePairListConstIterator : 0; +} + +QList QSerialPortPrivate::standardBaudRates() +{ + QList ret; + const QList baudRatePairs = standardBaudRatePairList(); + + foreach (qint32 baudRatePair, baudRatePairs) { + ret.append(baudRatePair); + } + + return ret; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport_win_p.h b/libs/serialport/qserialport_win_p.h new file mode 100644 index 0000000000000000000000000000000000000000..a59ea9a7bc7e35a7e57e3c43c5c11376f3326d97 --- /dev/null +++ b/libs/serialport/qserialport_win_p.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_WIN_P_H +#define QSERIALPORT_WIN_P_H + +#include "qserialport_p.h" + +#include + +#ifndef Q_OS_WINCE +#include +QT_BEGIN_NAMESPACE +class QWinEventNotifier; +#else +#include +QT_BEGIN_NAMESPACE +class QThread; +#endif + +#ifndef Q_OS_WINCE +class AbstractOverlappedEventNotifier; +#endif + +class QSerialPortPrivate : public QSerialPortPrivateData +{ +public: + QSerialPortPrivate(QSerialPort *q); + + bool open(QIODevice::OpenMode mode); + void close(); + + QSerialPort::PinoutSignals pinoutSignals() const; + + bool setDataTerminalReady(bool set); + bool setRequestToSend(bool set); + + bool flush(); + bool clear(QSerialPort::Directions dir); + + bool sendBreak(int duration); + bool setBreakEnabled(bool set); + + qint64 systemInputQueueSize () const; + qint64 systemOutputQueueSize () const; + + qint64 bytesAvailable() const; + + qint64 readFromBuffer(char *data, qint64 maxSize); + qint64 writeToBuffer(const char *data, qint64 maxSize); + + bool waitForReadyRead(int msec); + bool waitForBytesWritten(int msec); + + bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir); + 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 processIoErrors(bool error); +#ifndef Q_OS_WINCE + bool startAsyncRead(); + bool startAsyncWrite(int maxSize = INT_MAX); + bool completeAsyncRead(DWORD numberOfBytes); + bool completeAsyncWrite(DWORD numberOfBytes); + AbstractOverlappedEventNotifier *lookupFreeWriteCompletionNotifier(); + AbstractOverlappedEventNotifier *lookupCommEventNotifier(); + AbstractOverlappedEventNotifier *lookupReadCompletionNotifier(); +#else + bool notifyRead(); + bool notifyWrite(int maxSize = INT_MAX); +#endif + + static QString portNameToSystemLocation(const QString &port); + static QString portNameFromSystemLocation(const QString &location); + + static qint32 baudRateFromSetting(qint32 setting); + static qint32 settingFromBaudRate(qint32 baudRate); + + static QList standardBaudRates(); + + DCB currentDcb; + DCB restoredDcb; + COMMTIMEOUTS currentCommTimeouts; + COMMTIMEOUTS restoredCommTimeouts; + HANDLE descriptor; + bool parityErrorOccurred; + +#ifndef Q_OS_WINCE + QHash notifiers; + qint64 actualReadBufferSize; + qint64 actualWriteBufferSize; + qint64 acyncWritePosition; + bool readyReadEmitted; + bool writeSequenceStarted; +#else + QThread *eventNotifier; + QMutex settingsChangeMutex; +#endif + +private: + bool updateDcb(); + bool updateCommTimeouts(); + + void detectDefaultSettings(); + QSerialPort::SerialPortError decodeSystemError() const; + +#ifndef Q_OS_WINCE + bool waitAnyEvent(int msecs, bool *timedOut, + AbstractOverlappedEventNotifier **triggeredNotifier); +#else + bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut); +#endif + +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_WIN_P_H diff --git a/libs/serialport/qserialport_wince.cpp b/libs/serialport/qserialport_wince.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78d2746b16cb32985dcca0b8c944e950069c1436 --- /dev/null +++ b/libs/serialport/qserialport_wince.cpp @@ -0,0 +1,509 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_win_p.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QSerialPortPrivate; + +class CommEventNotifier : public QThread +{ + Q_OBJECT +signals: + void eventMask(quint32 mask); + +public: + CommEventNotifier(DWORD mask, QSerialPortPrivate *d, QObject *parent) + : QThread(parent), dptr(d), running(true) { + connect(this, SIGNAL(eventMask(quint32)), this, SLOT(processNotification(quint32))); + ::SetCommMask(dptr->descriptor, mask); + } + + virtual ~CommEventNotifier() { + running = false; + ::SetCommMask(dptr->descriptor, 0); + wait(); + } + +protected: + void run() Q_DECL_OVERRIDE { + DWORD mask = 0; + while (running) { + if (::WaitCommEvent(dptr->descriptor, &mask, FALSE)) { + // Wait until complete the operation changes the port settings, + // see updateDcb(). + dptr->settingsChangeMutex.lock(); + dptr->settingsChangeMutex.unlock(); + emit eventMask(quint32(mask)); + } + } + } + +private slots: + void processNotification(quint32 eventMask) { + + bool error = false; + + // Check for unexpected event. This event triggered when pulled previously + // opened device from the system, when opened as for not to read and not to + // write options and so forth. + if ((eventMask == 0) + || ((eventMask & (EV_ERR | EV_RXCHAR | EV_TXEMPTY)) == 0)) { + error = true; + } + + if (error || (EV_ERR & eventMask)) + dptr->processIoErrors(error); + if (EV_RXCHAR & eventMask) + dptr->notifyRead(); + if (EV_TXEMPTY & eventMask) + dptr->notifyWrite(QSerialPortPrivateData::WriteChunkSize); + } + +private: + QSerialPortPrivate *dptr; + mutable bool running; +}; + +class WaitCommEventBreaker : public QThread +{ + Q_OBJECT +public: + WaitCommEventBreaker(HANDLE descriptor, int timeout, QObject *parent = 0) + : QThread(parent), descriptor(descriptor), timeout(timeout), worked(false) { + start(); + } + + virtual ~WaitCommEventBreaker() { + stop(); + wait(); + } + + void stop() { + exit(0); + } + + bool isWorked() const { + return worked; + } + +protected: + void run() { + QTimer timer; + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(processTimeout()), Qt::DirectConnection); + timer.start(timeout); + exec(); + worked = true; + } + +private slots: + void processTimeout() { + ::SetCommMask(descriptor, 0); + stop(); + } + +private: + HANDLE descriptor; + int timeout; + mutable bool worked; +}; + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , descriptor(INVALID_HANDLE_VALUE) + , parityErrorOccurred(false) + , eventNotifier(0) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD eventMask = EV_ERR; + + if (mode & QIODevice::ReadOnly) { + desiredAccess |= GENERIC_READ; + eventMask |= EV_RXCHAR; + } + if (mode & QIODevice::WriteOnly) { + desiredAccess |= GENERIC_WRITE; + eventMask |= EV_TXEMPTY; + } + + descriptor = ::CreateFile(reinterpret_cast(systemLocation.utf16()), + desiredAccess, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (!::GetCommState(descriptor, &restoredDcb)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + currentDcb = restoredDcb; + currentDcb.fBinary = true; + currentDcb.fInX = false; + currentDcb.fOutX = false; + currentDcb.fAbortOnError = false; + currentDcb.fNull = false; + currentDcb.fErrorChar = false; + + if (!updateDcb()) + return false; + + if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + ::memset(¤tCommTimeouts, 0, sizeof(currentCommTimeouts)); + currentCommTimeouts.ReadIntervalTimeout = MAXDWORD; + + if (!updateCommTimeouts()) + return false; + + eventNotifier = new CommEventNotifier(eventMask, this, q_ptr); + eventNotifier->start(); + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + if (eventNotifier) { + eventNotifier->deleteLater(); + eventNotifier = 0; + } + + if (settingsRestoredOnClose) { + ::SetCommState(descriptor, &restoredDcb); + ::SetCommTimeouts(descriptor, &restoredCommTimeouts); + } + + ::CloseHandle(descriptor); + descriptor = INVALID_HANDLE_VALUE; +} + +bool QSerialPortPrivate::flush() +{ + return notifyWrite() && ::FlushFileBuffers(descriptor); +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + DWORD flags = 0; + if (dir & QSerialPort::Input) + flags |= PURGE_RXABORT | PURGE_RXCLEAR; + if (dir & QSerialPort::Output) + flags |= PURGE_TXABORT | PURGE_TXCLEAR; + return ::PurgeComm(descriptor, flags); +} + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return readBuffer.size(); +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + if (readBuffer.isEmpty()) + return 0; + + if (maxSize == 1) { + *data = readBuffer.getChar(); + return 1; + } + + const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize); + qint64 readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), + readBuffer.nextDataBlockSize()); + ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + } + + return readSoFar; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + char *ptr = writeBuffer.reserve(maxSize); + if (maxSize == 1) + *ptr = *data; + else + ::memcpy(ptr, data, maxSize); + + // trigger write sequence + notifyWrite(QSerialPortPrivateData::WriteChunkSize); + + return maxSize; +} + +bool QSerialPortPrivate::waitForReadyRead(int msec) +{ + if (!readBuffer.isEmpty()) + return true; + + QElapsedTimer stopWatch; + + stopWatch.start(); + + forever { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, + true, !writeBuffer.isEmpty(), + timeoutValue(msec, stopWatch.elapsed()), + &timedOut)) { + return false; + } + if (readyToRead) { + if (notifyRead()) + return true; + } + if (readyToWrite) + notifyWrite(WriteChunkSize); + } + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msec) +{ + if (writeBuffer.isEmpty()) + return false; + + QElapsedTimer stopWatch; + + stopWatch.start(); + + forever { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, + true, !writeBuffer.isEmpty(), + timeoutValue(msec, stopWatch.elapsed()), + &timedOut)) { + return false; + } + if (readyToRead) { + if (!notifyRead()) + return false; + } + if (readyToWrite) { + if (notifyWrite(WriteChunkSize)) + return true; + } + } + return false; +} + +bool QSerialPortPrivate::notifyRead() +{ + DWORD bytesToRead = (policy == QSerialPort::IgnorePolicy) ? ReadChunkSize : 1; + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the port. + return false; + } + } + + char *ptr = readBuffer.reserve(bytesToRead); + + DWORD readBytes = 0; + BOOL sucessResult = ::ReadFile(descriptor, ptr, bytesToRead, &readBytes, NULL); + + if (!sucessResult) { + readBuffer.truncate(bytesToRead); + q_ptr->setError(QSerialPort::ReadError); + return false; + } + + readBuffer.truncate(readBytes); + + // Process emulate policy. + if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) { + + parityErrorOccurred = false; + + switch (policy) { + case QSerialPort::SkipPolicy: + readBuffer.getChar(); + return true; + case QSerialPort::PassZeroPolicy: + readBuffer.getChar(); + readBuffer.putChar('\0'); + break; + case QSerialPort::StopReceivingPolicy: + // FIXME: Maybe need disable read notifier? + break; + default: + break; + } + } + + if (readBytes > 0) + emit q_ptr->readyRead(); + + return true; +} + +bool QSerialPortPrivate::notifyWrite(int maxSize) +{ + int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize); + + const char *ptr = writeBuffer.readPointer(); + + DWORD bytesWritten = 0; + if (!::WriteFile(descriptor, ptr, nextSize, &bytesWritten, NULL)) { + q_ptr->setError(QSerialPort::WriteError); + return false; + } + + writeBuffer.free(bytesWritten); + + if (bytesWritten > 0) + emit q_ptr->bytesWritten(bytesWritten); + + return true; +} + +bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + DWORD eventMask = 0; + // FIXME: Here the situation is not properly handled with zero timeout: + // breaker can work out before you call a method WaitCommEvent() + // and so it will loop forever! + WaitCommEventBreaker breaker(descriptor, qMax(msecs, 0)); + ::WaitCommEvent(descriptor, &eventMask, NULL); + breaker.stop(); + + if (breaker.isWorked()) + *timedOut = true; + + if (!breaker.isWorked()) { + if (checkRead) { + Q_ASSERT(selectForRead); + *selectForRead = eventMask & EV_RXCHAR; + } + if (checkWrite) { + Q_ASSERT(selectForWrite); + *selectForWrite = eventMask & EV_TXEMPTY; + } + + return true; + } + + return false; +} + +bool QSerialPortPrivate::updateDcb() +{ + QMutexLocker locker(&settingsChangeMutex); + + DWORD eventMask = 0; + // Save the event mask + if (!::GetCommMask(descriptor, &eventMask)) + return false; + + // Break event notifier from WaitCommEvent + ::SetCommMask(descriptor, 0); + // Change parameters + bool ret = ::SetCommState(descriptor, ¤tDcb); + if (!ret) + q_ptr->setError(decodeSystemError()); + // Restore the event mask + ::SetCommMask(descriptor, eventMask); + + return ret; +} + +bool QSerialPortPrivate::updateCommTimeouts() +{ + if (!::SetCommTimeouts(descriptor, ¤tCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +static const QLatin1String defaultPathPostfix(":"); + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + QString ret = port; + if (!ret.contains(defaultPathPostfix)) + ret.append(defaultPathPostfix); + return ret; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + QString ret = location; + if (ret.contains(defaultPathPostfix)) + ret.remove(defaultPathPostfix); + return ret; +} + +#include "qserialport_wince.moc" + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportglobal.h b/libs/serialport/qserialportglobal.h new file mode 100644 index 0000000000000000000000000000000000000000..34c5ba4ffecda47477ac38f1595cbd2958088ad1 --- /dev/null +++ b/libs/serialport/qserialportglobal.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORTGLOBAL_H +#define QSERIALPORTGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_SERIALPORT_LIB) +# define Q_SERIALPORT_EXPORT Q_DECL_EXPORT +# else +//# define Q_SERIALPORT_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_SERIALPORT_EXPORT +#endif +# define Q_SERIALPORT_EXPORT +// The macro has been available only since Qt 5.0 +#ifndef Q_DECL_OVERRIDE +#define Q_DECL_OVERRIDE +#endif + +QT_END_NAMESPACE + +#endif // QSERIALPORTGLOBAL_H diff --git a/libs/serialport/qserialportinfo.cpp b/libs/serialport/qserialportinfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..241d344aea8131b659febfe37ec70456dd377e26 --- /dev/null +++ b/libs/serialport/qserialportinfo.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport.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() + : d_ptr(new QSerialPortInfoPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ +QSerialPortInfo::QSerialPortInfo(const QSerialPortInfo &other) + : d_ptr(other.d_ptr ? new QSerialPortInfoPrivate(*other.d_ptr) : 0) +{ +} + +/*! + Constructs a QSerialPortInfo object from serial \a port. +*/ +QSerialPortInfo::QSerialPortInfo(const QSerialPort &port) + : d_ptr(new QSerialPortInfoPrivate) +{ + 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) + : d_ptr(new QSerialPortInfoPrivate) +{ + foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) { + if (name == serialPortInfo.portName()) { + *this = serialPortInfo; + break; + } + } +} + +/*! + 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. +*/ +QString QSerialPortInfo::portName() const +{ + Q_D(const QSerialPortInfo); + return !d ? QString() : d->portName; +} + +/*! + Returns the system location of the serial port. +*/ +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. +*/ +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. +*/ +QString QSerialPortInfo::manufacturer() const +{ + Q_D(const QSerialPortInfo); + return !d ? QString() : d->manufacturer; +} + +/*! + Returns the 16-bit vendor number for the serial port, if available; + otherwise returns zero. +*/ +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. +*/ +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. +*/ +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. +*/ +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. +*/ + +/*! + \fn bool QSerialPortInfo::isBusy() const + + Returns true if serial port is busy; + otherwise returns false. +*/ + +/*! + \fn bool QSerialPortInfo::isValid() const + + Returns true if serial port is present on system; + otherwise returns false. +*/ + +/*! + \fn QList QSerialPortInfo::standardBaudRates() + + Returns a list of available standard baud rates supported by + the current serial port. +*/ + +/*! + \fn QList QSerialPortInfo::availablePorts() + + Returns a list of available serial ports on the system. +*/ + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo.h b/libs/serialport/qserialportinfo.h new file mode 100644 index 0000000000000000000000000000000000000000..cf47939e663f9e7bc21bda972269efe0a28340eb --- /dev/null +++ b/libs/serialport/qserialportinfo.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORTINFO_H +#define QSERIALPORTINFO_H + +#include +#include + +#include +//#include + +QT_BEGIN_NAMESPACE + +class QSerialPort; +class QSerialPortInfoPrivate; +class QSerialPortInfoPrivateDeleter; + +class Q_SERIALPORT_EXPORT 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; + + quint16 vendorIdentifier() const; + quint16 productIdentifier() const; + + bool hasVendorIdentifier() const; + bool hasProductIdentifier() const; + + bool isNull() const; + bool isBusy() const; + bool isValid() const; + + static QList standardBaudRates(); + static QList availablePorts(); + +private: + QScopedPointer d_ptr; +}; + +inline bool QSerialPortInfo::isNull() const +{ return !d_ptr; } + +QT_END_NAMESPACE + +#endif // QSERIALPORTINFO_H diff --git a/libs/serialport/qserialportinfo_mac.cpp b/libs/serialport/qserialportinfo_mac.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a751dfcaf4dbf84cbd4870d1bb0d7be2d22a8ed --- /dev/null +++ b/libs/serialport/qserialportinfo_mac.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" + +#include + +#include +#include + +#include +#include // for kIOPropertyProductNameKey +#include +#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) +# include +#endif +#include + +QT_BEGIN_NAMESPACE + +enum { MATCHING_PROPERTIES_COUNT = 6 }; + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + + int matchingPropertiesCounter = 0; + + + ::CFMutableDictionaryRef matching = ::IOServiceMatching(kIOSerialBSDServiceValue); + if (!matching) + return serialPortInfoList; + + ::CFDictionaryAddValue(matching, + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDAllTypes)); + + io_iterator_t iter = 0; + kern_return_t kr = ::IOServiceGetMatchingServices(kIOMasterPortDefault, + matching, + &iter); + + if (kr != kIOReturnSuccess) + return serialPortInfoList; + + io_registry_entry_t service; + + while ((service = ::IOIteratorNext(iter))) { + + ::CFTypeRef device = 0; + ::CFTypeRef portName = 0; + ::CFTypeRef description = 0; + ::CFTypeRef manufacturer = 0; + ::CFTypeRef vendorIdentifier = 0; + ::CFTypeRef productIdentifier = 0; + + io_registry_entry_t entry = service; + + // Find MacOSX-specific properties names. + do { + + if (!device) { + device = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kIOCalloutDeviceKey), + kCFAllocatorDefault, + 0); + if (device) + ++matchingPropertiesCounter; + } + + if (!portName) { + portName = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kIOTTYDeviceKey), + kCFAllocatorDefault, + 0); + if (portName) + ++matchingPropertiesCounter; + } + + if (!description) { + description = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kIOPropertyProductNameKey), + kCFAllocatorDefault, + 0); + if (!description) + description = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBProductString), + kCFAllocatorDefault, + 0); + if (!description) + description = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR("BTName"), + kCFAllocatorDefault, + 0); + + if (description) + ++matchingPropertiesCounter; + } + + if (!manufacturer) { + manufacturer = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBVendorString), + kCFAllocatorDefault, + 0); + if (manufacturer) + ++matchingPropertiesCounter; + + } + + if (!vendorIdentifier) { + vendorIdentifier = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBVendorID), + kCFAllocatorDefault, + 0); + if (vendorIdentifier) + ++matchingPropertiesCounter; + + } + + if (!productIdentifier) { + productIdentifier = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBProductID), + kCFAllocatorDefault, + 0); + if (productIdentifier) + ++matchingPropertiesCounter; + + } + + // If all matching properties is found, then force break loop. + if (matchingPropertiesCounter == MATCHING_PROPERTIES_COUNT) + break; + + kr = ::IORegistryEntryGetParentEntry(entry, kIOServicePlane, &entry); + + } while (kr == kIOReturnSuccess); + + (void) ::IOObjectRelease(entry); + + // Convert from MacOSX-specific properties to Qt4-specific. + if (matchingPropertiesCounter > 0) { + + QSerialPortInfo serialPortInfo; + QByteArray buffer(MAXPATHLEN, 0); + + if (device) { + if (::CFStringGetCString(CFStringRef(device), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->device = QString::fromUtf8(buffer); + } + ::CFRelease(device); + } + + if (portName) { + if (::CFStringGetCString(CFStringRef(portName), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->portName = QString::fromUtf8(buffer); + } + ::CFRelease(portName); + } + + if (description) { + if (::CFStringGetCString(CFStringRef(description), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->description = QString::fromUtf8(buffer); + } + ::CFRelease(description); + } + + if (manufacturer) { + if (::CFStringGetCString(CFStringRef(manufacturer), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->manufacturer = QString::fromUtf8(buffer); + } + ::CFRelease(manufacturer); + } + + quint16 value = 0; + + if (vendorIdentifier) { + serialPortInfo.d_ptr->hasVendorIdentifier = ::CFNumberGetValue(CFNumberRef(vendorIdentifier), kCFNumberIntType, &value); + if (serialPortInfo.d_ptr->hasVendorIdentifier) + serialPortInfo.d_ptr->vendorIdentifier = value; + + ::CFRelease(vendorIdentifier); + } + + if (productIdentifier) { + serialPortInfo.d_ptr->hasProductIdentifier = ::CFNumberGetValue(CFNumberRef(productIdentifier), kCFNumberIntType, &value); + if (serialPortInfo.d_ptr->hasProductIdentifier) + serialPortInfo.d_ptr->productIdentifier = value; + + ::CFRelease(productIdentifier); + } + + serialPortInfoList.append(serialPortInfo); + } + + (void) ::IOObjectRelease(service); + } + + (void) ::IOObjectRelease(iter); + + return serialPortInfoList; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_p.h b/libs/serialport/qserialportinfo_p.h new file mode 100644 index 0000000000000000000000000000000000000000..1f12e69bac882758d7264ea7ad36909729199e8b --- /dev/null +++ b/libs/serialport/qserialportinfo_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORTINFO_P_H +#define QSERIALPORTINFO_P_H + +#include + +QT_BEGIN_NAMESPACE + +class QSerialPortInfoPrivate +{ +public: + QSerialPortInfoPrivate() + : vendorIdentifier(0) + , productIdentifier(0) + , hasVendorIdentifier(false) + , hasProductIdentifier(false) + {} + + ~QSerialPortInfoPrivate() {} + + QString portName; + QString device; + QString description; + QString manufacturer; + + quint16 vendorIdentifier; + quint16 productIdentifier; + + bool hasVendorIdentifier; + bool hasProductIdentifier; +}; + +class QSerialPortInfoPrivateDeleter +{ +public: + static void cleanup(QSerialPortInfoPrivate *p) { + delete p; + } +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORTINFO_P_H diff --git a/libs/serialport/qserialportinfo_symbian.cpp b/libs/serialport/qserialportinfo_symbian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55120485e68235b98fd67c5b1443ea2549cca72d --- /dev/null +++ b/libs/serialport/qserialportinfo_symbian.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_symbian_p.h" + +#include +//#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +// Physical device driver. +#ifdef __WINS__ +_LIT(KPddName, "ECDRV"); +#else // defined (__EPOC32__) +_LIT(KPddName, "EUART"); +#endif + +// Logical native device driver. +_LIT(KLddName,"ECOMM"); + +// Modules names. +_LIT(KRS232ModuleName , "ECUART"); +_LIT(KBluetoothModuleName , "BTCOMM"); +_LIT(KInfraRedModuleName , "IRCOMM"); +_LIT(KACMModuleName, "ECACM"); + +// Return false on error load. +static bool loadDevices() +{ + TInt r = KErrNone; +#ifdef __WINS__ + RFs fileServer; + r = User::LeaveIfError(fileServer.Connect()); + if (r != KErrNone) + return false; + fileServer.Close (); +#endif + + r = User::LoadPhysicalDevice(KPddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + + r = User::LoadLogicalDevice(KLddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + +#ifndef __WINS__ + r = StartC32(); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); +#endif + + return true; +} + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + + if (!loadDevices()) + return serialPortInfoList; + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) + return serialPortInfoList; //User::LeaveIfError(r); + + TSerialInfo nativeSerialInfo; // Native Symbian OS port info class. + QString s("%1::%2"); + + // FIXME: Get info about RS232 ports. + r = server.LoadCommModule(KRS232ModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KRS232ModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device; + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + // FIXME: Get info about Bluetooth ports. + r = server.LoadCommModule(KBluetoothModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KBluetoothModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device; + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + // FIXME: Get info about InfraRed ports. + r = server.LoadCommModule(KInfraRedModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KInfraRedModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device; + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + // FIXME: Get info about ACM ports. + r = server.LoadCommModule(KACMModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KACMModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(serialPortInfo.d_ptr->device); + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + return serialPortInfoList; +} + +QList QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + if (!loadDevices()) + return false; + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) + return false; + + RComm port; + TPtrC portName(static_cast(systemLocation().utf16()), systemLocation().length()); + r = port.Open(server, portName, ECommExclusive); + if (r == KErrNone) + port.Close(); + return r == KErrLocked; +} + +bool QSerialPortInfo::isValid() const +{ + if (!loadDevices()) + return false; + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) + return false; + + RComm port; + TPtrC portName(static_cast(systemLocation().utf16()), systemLocation().length()); + r = port.Open(server, portName, ECommExclusive); + if (r == KErrNone) + port.Close(); + return r == KErrNone || r == KErrLocked; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_unix.cpp b/libs/serialport/qserialportinfo_unix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d56f4e22bde05311a6912aa0fe328b8dc5d6f3e --- /dev/null +++ b/libs/serialport/qserialportinfo_unix.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qttylocker_unix_p.h" +#include "qserialport_unix_p.h" +#include + +#ifndef Q_OS_MAC + +#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV) +extern "C" +{ +#include +} +#else +#include +#include +#endif + +#endif // Q_OS_MAC + +QT_BEGIN_NAMESPACE + +#ifndef Q_OS_MAC + +#if !(defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)) + +static inline const QStringList& filtersOfDevices() +{ + static const QStringList deviceFileNameFilterList = QStringList() + +# ifdef Q_OS_LINUX + << QLatin1String("ttyS*") // Standart UART 8250 and etc. + << QLatin1String("ttyUSB*") // Usb/serial converters PL2303 and etc. + << QLatin1String("ttyACM*") // CDC_ACM converters (i.e. Mobile Phones). + << QLatin1String("ttyGS*") // Gadget serial device (i.e. Mobile Phones with gadget serial driver). + << QLatin1String("ttyMI*") // MOXA pci/serial converters. + << QLatin1String("ttyAMA*") // AMBA serial device for embedded platform on ARM (i.e. Raspberry Pi). + << QLatin1String("rfcomm*") // Bluetooth serial device. + << QLatin1String("ircomm*"); // IrDA serial device. +# elif defined (Q_OS_FREEBSD) + << QLatin1String("cu*"); +# else + ; // Here for other *nix OS. +# endif + + return deviceFileNameFilterList; +} + +#endif + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + +#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV) + + // White list for devices without a parent + static const QString rfcommDeviceName(QLatin1String("rfcomm")); + + struct ::udev *udev = ::udev_new(); + if (udev) { + + struct ::udev_enumerate *enumerate = + ::udev_enumerate_new(udev); + + if (enumerate) { + + ::udev_enumerate_add_match_subsystem(enumerate, "tty"); + ::udev_enumerate_scan_devices(enumerate); + + struct ::udev_list_entry *devices = + ::udev_enumerate_get_list_entry(enumerate); + + struct ::udev_list_entry *dev_list_entry; + udev_list_entry_foreach(dev_list_entry, devices) { + + struct ::udev_device *dev = + ::udev_device_new_from_syspath(udev, + ::udev_list_entry_get_name(dev_list_entry)); + + if (dev) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = + QLatin1String(::udev_device_get_devnode(dev)); + serialPortInfo.d_ptr->portName = + QLatin1String(::udev_device_get_sysname(dev)); + + struct ::udev_device *parentdev = ::udev_device_get_parent(dev); + + bool canAppendToList = true; + + if (parentdev) { + + QLatin1String subsys(::udev_device_get_subsystem(parentdev)); + + if (subsys == QLatin1String("usb-serial") + || subsys == QLatin1String("usb")) { // USB bus type + // Append this devices and try get additional information about them. + serialPortInfo.d_ptr->description = QString( + QLatin1String(::udev_device_get_property_value(dev, + "ID_MODEL"))).replace('_', ' '); + serialPortInfo.d_ptr->manufacturer = QString( + QLatin1String(::udev_device_get_property_value(dev, + "ID_VENDOR"))).replace('_', ' '); + + serialPortInfo.d_ptr->vendorIdentifier = + QString::fromLatin1(::udev_device_get_property_value(dev, + "ID_VENDOR_ID")).toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16); + + serialPortInfo.d_ptr->productIdentifier = + QString::fromLatin1(::udev_device_get_property_value(dev, + "ID_MODEL_ID")).toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); + + } else if (subsys == QLatin1String("pnp")) { // PNP bus type + // Append this device. + // FIXME: How to get additional information about serial devices + // with this subsystem? + } else if (subsys == QLatin1String("platform")) { // Platform 'pseudo' bus for legacy device. + // Skip this devices because this type of subsystem does + // not include a real physical serial device. + canAppendToList = false; + } else { // Others types of subsystems. + // Append this devices because we believe that any other types of + // subsystems provide a real serial devices. For example, for devices + // such as ttyGSx, its driver provide an empty subsystem name, but it + // devices is a real physical serial devices. + // FIXME: How to get additional information about serial devices + // with this subsystems? + } + } else { // Devices without a parent + if (serialPortInfo.d_ptr->portName.startsWith(rfcommDeviceName)) { // Bluetooth device + bool ok; + // Check for an unsigned decimal integer at the end of the device name: "rfcomm0", "rfcomm15" + // devices with negative and invalid numbers in the name are rejected + int portNumber = serialPortInfo.d_ptr->portName.mid(rfcommDeviceName.length()).toInt(&ok); + + if (!ok || (portNumber < 0) || (portNumber > 255)) { + canAppendToList = false; + } + } else { + canAppendToList = false; + } + } + + if (canAppendToList) + serialPortInfoList.append(serialPortInfo); + + ::udev_device_unref(dev); + } + + } + + ::udev_enumerate_unref(enumerate); + } + + ::udev_unref(udev); + } + +#elif defined (Q_OS_FREEBSD) && defined (HAVE_LIBUSB) + // TODO: Implement me. +#else + + QDir devDir(QLatin1String("/dev")); + if (devDir.exists()) { + + devDir.setNameFilters(filtersOfDevices()); + devDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks); + + QStringList foundDevices; // Found devices list. + + foreach (const QFileInfo &deviceFileInfo, devDir.entryInfoList()) { + QString deviceFilePath = deviceFileInfo.absoluteFilePath(); + if (!foundDevices.contains(deviceFilePath)) { + foundDevices.append(deviceFilePath); + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = deviceFilePath; + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath); + + // Get description, manufacturer, vendor identifier, product + // identifier are not supported. + + serialPortInfoList.append(serialPortInfo); + + } + } + } + +#endif + + return serialPortInfoList; +} + +#endif // Q_OS_MAC + +// common part + +QList QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + bool currentPid = false; + return QTtyLocker::isLocked(portName().toLocal8Bit().constData(), ¤tPid); +} + +bool QSerialPortInfo::isValid() const +{ + QFile f(systemLocation()); + return f.exists(); +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_win.cpp b/libs/serialport/qserialportinfo_win.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ca1f5ef4c1cc16b3322a9ad5d9be7354f266aa1 --- /dev/null +++ b/libs/serialport/qserialportinfo_win.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_win_p.h" + +#ifndef Q_OS_WINCE +#include +#include +#endif + +#include +#include + +QT_BEGIN_NAMESPACE + +#ifndef Q_OS_WINCE + +static const GUID guidsArray[] = +{ + // Windows Ports Class GUID + { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, + // Virtual Ports Class GUID (i.e. com0com and etc) + { 0xDF799E12, 0x3C56, 0x421B, { 0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78 } }, + // Windows Modems Class GUID + { 0x4D36E96D, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, + // Eltima Virtual Serial Port Driver v4 GUID + { 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } }, + // Advanced Virtual COM Port GUID + { 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } }, +}; + +static QVariant deviceRegistryProperty(HDEVINFO deviceInfoSet, + PSP_DEVINFO_DATA deviceInfoData, + DWORD property) +{ + DWORD dataType = 0; + DWORD dataSize = 0; + ::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, + property, &dataType, NULL, 0, &dataSize); + QByteArray data(dataSize, 0); + if (!::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, NULL, + reinterpret_cast(data.data()), + dataSize, NULL) + || !dataSize) { + return QVariant(); + } + + switch (dataType) { + + case REG_EXPAND_SZ: + case REG_SZ: { + return QVariant(QString::fromWCharArray(reinterpret_cast(data.constData()))); + } + + case REG_MULTI_SZ: { + QStringList list; + int i = 0; + forever { + QString s = QString::fromWCharArray(reinterpret_cast(data.constData()) + i); + i += s.length() + 1; + if (s.isEmpty()) + break; + list.append(s); + } + return QVariant(list); + } + + default: + break; + } + + return QVariant(); +} + +static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) +{ + static const wchar_t portKeyName[] = L"PortName"; + + const HKEY key = ::SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL, + 0, DIREG_DEV, KEY_READ); + if (key == INVALID_HANDLE_VALUE) + return QString(); + + DWORD dataSize; + if (::RegQueryValueEx(key, portKeyName, NULL, NULL, NULL, &dataSize) != ERROR_SUCCESS) { + ::RegCloseKey(key); + return QString(); + } + + QByteArray data(dataSize, 0); + + if (::RegQueryValueEx(key, portKeyName, NULL, NULL, + reinterpret_cast(data.data()), &dataSize) != ERROR_SUCCESS) { + ::RegCloseKey(key); + return QString(); + } + ::RegCloseKey(key); + return QString::fromWCharArray(((const wchar_t *)data.constData())); +} + +QList QSerialPortInfo::availablePorts() +{ + static const QString vendorIdentifierPrefix(QLatin1String("VID_")); + static const int vendorIdentifierSize = 4; + static const QString productIdentifierPrefix(QLatin1String("PID_")); + static const int productIdentifierSize = 4; + + QList serialPortInfoList; + static const int guidCount = sizeof(guidsArray)/sizeof(guidsArray[0]); + + for (int i = 0; i < guidCount; ++i) { + const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(&guidsArray[i], NULL, 0, DIGCF_PRESENT); + if (deviceInfoSet == INVALID_HANDLE_VALUE) + return serialPortInfoList; + + SP_DEVINFO_DATA deviceInfoData; + ::memset(&deviceInfoData, 0, sizeof(deviceInfoData)); + deviceInfoData.cbSize = sizeof(deviceInfoData); + + DWORD index = 0; + while (::SetupDiEnumDeviceInfo(deviceInfoSet, index++, &deviceInfoData)) { + QSerialPortInfo serialPortInfo; + + QString s = devicePortName(deviceInfoSet, &deviceInfoData); + if (s.isEmpty() || s.contains(QLatin1String("LPT"))) + continue; + + serialPortInfo.d_ptr->portName = s; + serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(s); + serialPortInfo.d_ptr->description = + deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC).toString(); + serialPortInfo.d_ptr->manufacturer = + deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG).toString(); + + s = deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID).toStringList().first().toUpper(); + + int index = s.indexOf(vendorIdentifierPrefix); + if (index != -1) + serialPortInfo.d_ptr->vendorIdentifier = s.mid(index + vendorIdentifierPrefix.size(), vendorIdentifierSize) + .toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16); + + index = s.indexOf(productIdentifierPrefix); + if (index != -1) + serialPortInfo.d_ptr->productIdentifier = s.mid(index + productIdentifierPrefix.size(), productIdentifierSize) + .toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); + + serialPortInfoList.append(serialPortInfo); + } + ::SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + return serialPortInfoList; +} + +#endif + +// common part + +QList QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + const HANDLE descriptor = ::CreateFile(reinterpret_cast(systemLocation().utf16()), + GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + if (::GetLastError() == ERROR_ACCESS_DENIED) + return true; + } else { + ::CloseHandle(descriptor); + } + return false; +} + +bool QSerialPortInfo::isValid() const +{ + const HANDLE descriptor = ::CreateFile(reinterpret_cast(systemLocation().utf16()), + GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + if (::GetLastError() != ERROR_ACCESS_DENIED) + return false; + } else { + ::CloseHandle(descriptor); + } + return true; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_wince.cpp b/libs/serialport/qserialportinfo_wince.cpp new file mode 100644 index 0000000000000000000000000000000000000000..279aceae414064ede27ec745f1c4bf40028408f8 --- /dev/null +++ b/libs/serialport/qserialportinfo_wince.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_win_p.h" + +#include + +QT_BEGIN_NAMESPACE + +static QString findDescription(HKEY parentKeyHandle, const QString &subKey) +{ + const static QString valueName(QLatin1String("FriendlyName")); + + QString result; + HKEY hSubKey = 0; + LONG res = ::RegOpenKeyEx(parentKeyHandle, reinterpret_cast(subKey.utf16()), + 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hSubKey); + + if (res == ERROR_SUCCESS) { + + DWORD dataType = 0; + DWORD dataSize = 0; + res = ::RegQueryValueEx(hSubKey, reinterpret_cast(valueName.utf16()), + NULL, &dataType, NULL, &dataSize); + + if (res == ERROR_SUCCESS) { + QByteArray data(dataSize, 0); + res = ::RegQueryValueEx(hSubKey, reinterpret_cast(valueName.utf16()), + NULL, NULL, + reinterpret_cast(data.data()), + &dataSize); + + if (res == ERROR_SUCCESS) { + switch (dataType) { + case REG_EXPAND_SZ: + case REG_SZ: + if (dataSize) + result = QString::fromWCharArray(reinterpret_cast(data.constData())); + break; + default: + break; + } + } + } else { + DWORD index = 0; + dataSize = 255; // Max. key length (see MSDN). + QByteArray data(dataSize, 0); + while (::RegEnumKeyEx(hSubKey, index++, + reinterpret_cast(data.data()), &dataSize, + NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { + + result = findDescription(hSubKey, + QString::fromUtf16(reinterpret_cast(data.data()), dataSize)); + if (!result.isEmpty()) + break; + } + } + ::RegCloseKey(hSubKey); + } + return result; +} + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + + DEVMGR_DEVICE_INFORMATION di; + di.dwSize = sizeof(di); + const HANDLE hSearch = ::FindFirstDevice(DeviceSearchByLegacyName, + L"COM*", + &di); + if (hSearch != INVALID_HANDLE_VALUE) { + do { + QSerialPortInfo serialPortInfo; + serialPortInfo.d_ptr->device = QString::fromWCharArray(di.szLegacyName); + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(serialPortInfo.d_ptr->device); + serialPortInfo.d_ptr->description = findDescription(HKEY_LOCAL_MACHINE, + QString::fromWCharArray(di.szDeviceKey)); + + // Get manufacturer, vendor identifier, product identifier are not + // possible. + + serialPortInfoList.append(serialPortInfo); + + } while (::FindNextDevice(hSearch, &di)); + ::FindClose(hSearch); + } + + return serialPortInfoList; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qt4support/install-helper.pri b/libs/serialport/qt4support/install-helper.pri new file mode 100644 index 0000000000000000000000000000000000000000..52577095e3b69e9af0786de0525d104a03d59a3c --- /dev/null +++ b/libs/serialport/qt4support/install-helper.pri @@ -0,0 +1,43 @@ +QTSERIALPORT_PROJECT_INCLUDEDIR = $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort +QTSERIALPORT_PROJECT_INCLUDEDIR ~=s,/,$$QMAKE_DIR_SEP, + +system("$$QMAKE_MKDIR $$QTSERIALPORT_PROJECT_INCLUDEDIR") + +for(header_file, PUBLIC_HEADERS) { + header_file ~=s,/,$$QMAKE_DIR_SEP, + system("$$QMAKE_COPY \"$${header_file}\" \"$$QTSERIALPORT_PROJECT_INCLUDEDIR\"") +} + +# This is a quick workaround for generating forward header with Qt4. + +unix { + system("echo \'$${LITERAL_HASH}include \"qserialport.h\"\' > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\"") + system("echo \'$${LITERAL_HASH}include \"qserialportinfo.h\"\' > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"") +} win32 { + system("echo $${LITERAL_HASH}include \"qserialport.h\" > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\"") + system("echo $${LITERAL_HASH}include \"qserialportinfo.h\" > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"") +} + +PUBLIC_HEADERS += \ + $$PUBLIC_HEADERS \ + \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\" \ + \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\" + +target_headers.files = $$PUBLIC_HEADERS +target_headers.path = $$[QT_INSTALL_PREFIX]/include/QtSerialPort +INSTALLS += target_headers + +mkspecs_features.files = $$QTSERIALPORT_PROJECT_ROOT/src/serialport/qt4support/serialport.prf +mkspecs_features.path = $$[QT_INSTALL_DATA]/mkspecs/features +INSTALLS += mkspecs_features + +win32 { + dlltarget.path = $$[QT_INSTALL_BINS] + INSTALLS += dlltarget +} + +target.path = $$[QT_INSTALL_LIBS] +INSTALLS += target + +INCLUDEPATH += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort +DEFINES += QT_BUILD_SERIALPORT_LIB diff --git a/libs/serialport/qt4support/qringbuffer_p.h b/libs/serialport/qt4support/qringbuffer_p.h new file mode 100644 index 0000000000000000000000000000000000000000..ddd10e54358ceb10483e14f2a6bbc3ab0aabc03e --- /dev/null +++ b/libs/serialport/qt4support/qringbuffer_p.h @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore 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$ +** +****************************************************************************/ + +#ifndef QRINGBUFFER_P_H +#define QRINGBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QRingBuffer +{ +public: + explicit inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) { + buffers << QByteArray(); + clear(); + } + + 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 (buffers.isEmpty()) { + length = 0; + return 0; + } + + if (pos >= bufferSize) { + length = 0; + return 0; + } + + // special case: it is in the first buffer + int nextDataBlockSizeValue = nextDataBlockSize(); + if (pos - head < nextDataBlockSizeValue) { + length = nextDataBlockSizeValue - pos; + return buffers.at(0).constData() + head + pos; + } + + // special case: we only had one buffer and tried to read over it + if (buffers.length() == 1) { + length = 0; + return 0; + } + + // skip the first + pos -= nextDataBlockSizeValue; + + // normal case: it is somewhere in the second to the-one-before-the-tailBuffer + for (int i = 1; i < tailBuffer; i++) { + if (pos >= buffers[i].size()) { + pos -= buffers[i].size(); + continue; + } + + length = buffers[i].length() - pos; + return buffers[i].constData() + pos; + } + + // it is in the tail buffer + length = tail - pos; + return buffers[tailBuffer].constData() + pos; + } + + inline void free(int bytes) { + bufferSize -= bytes; + if (bufferSize < 0) + bufferSize = 0; + + for (;;) { + int nextBlockSize = nextDataBlockSize(); + if (bytes < nextBlockSize) { + head += bytes; + if (head == tail && tailBuffer == 0) + head = tail = 0; + break; + } + + bytes -= nextBlockSize; + if (buffers.count() == 1) { + if (buffers.at(0).size() != basicBlockSize) + buffers[0].resize(basicBlockSize); + head = tail = 0; + tailBuffer = 0; + break; + } + + buffers.removeAt(0); + --tailBuffer; + head = 0; + } + + if (isEmpty()) + clear(); // try to minify/squeeze us + } + + inline char *reserve(int bytes) { + // if this is a fresh empty QRingBuffer + if (bufferSize == 0) { + buffers[0].resize(qMax(basicBlockSize, bytes)); + bufferSize += bytes; + tail = bytes; + return buffers[tailBuffer].data(); + } + + bufferSize += bytes; + + // if there is already enough space, simply return. + if (tail + bytes <= buffers.at(tailBuffer).size()) { + char *writePtr = buffers[tailBuffer].data() + tail; + tail += bytes; + return writePtr; + } + + // if our buffer isn't half full yet, simply resize it. + if (tail < buffers.at(tailBuffer).size() / 2) { + buffers[tailBuffer].resize(tail + bytes); + char *writePtr = buffers[tailBuffer].data() + tail; + tail += bytes; + return writePtr; + } + + // shrink this buffer to its current size + buffers[tailBuffer].resize(tail); + + // create a new QByteArray with the right size + buffers << QByteArray(); + ++tailBuffer; + buffers[tailBuffer].resize(qMax(basicBlockSize, bytes)); + tail = bytes; + return buffers[tailBuffer].data(); + } + + inline void truncate(int pos) { + if (pos < size()) + chop(size() - pos); + } + + inline void chop(int bytes) { + bufferSize -= bytes; + if (bufferSize < 0) + bufferSize = 0; + + for (;;) { + // special case: head and tail are in the same buffer + if (tailBuffer == 0) { + tail -= bytes; + if (tail <= head) + tail = head = 0; + return; + } + + if (bytes <= tail) { + tail -= bytes; + return; + } + + bytes -= tail; + buffers.removeAt(tailBuffer); + + --tailBuffer; + tail = buffers.at(tailBuffer).size(); + } + + if (isEmpty()) + clear(); // try to minify/squeeze us + } + + 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[0].resize(basicBlockSize); + head = basicBlockSize - 1; + ++tailBuffer; + } + buffers[0][head] = c; + ++bufferSize; + } + + inline int size() const { + return bufferSize; + } + + inline void clear() { + buffers.erase(buffers.begin() + 1, buffers.end()); + buffers[0].resize(0); + buffers[0].squeeze(); + + head = tail = 0; + tailBuffer = 0; + bufferSize = 0; + } + + inline int indexOf(char c) const { + int index = 0; + for (int i = 0; i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + + inline int indexOf(char c, int maxLength) const { + int index = 0; + int remain = qMin(size(), maxLength); + for (int i = 0; remain && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + if (remain < end - start) { + end = start + remain; + remain = 0; + } else { + remain -= end - start; + } + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + + inline int read(char *data, int maxLength) { + int bytesToRead = qMin(size(), maxLength); + int readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readPointer(); + int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize()); + if (data) + memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + free(bytesToReadFromThisBlock); + } + return readSoFar; + } + + inline QByteArray read(int maxLength) { + QByteArray tmp; + tmp.resize(qMin(maxLength, size())); + read(tmp.data(), tmp.size()); + return tmp; + } + + inline QByteArray readAll() { + return read(size()); + } + + // read an unspecified amount (will read the first buffer) + inline QByteArray read() { + if (bufferSize == 0) + return QByteArray(); + + // multiple buffers, just take the first one + if (head == 0 && tailBuffer != 0) { + QByteArray qba = buffers.takeFirst(); + --tailBuffer; + bufferSize -= qba.length(); + return qba; + } + + // one buffer with good value for head. Just take it. + if (head == 0 && tailBuffer == 0) { + QByteArray qba = buffers.takeFirst(); + qba.resize(tail); + buffers << QByteArray(); + bufferSize = 0; + tail = 0; + return qba; + } + + // Bad case: We have to memcpy. + // We can avoid by initializing the QRingBuffer with basicBlockSize of 0 + // and only using this read() function. + QByteArray qba(readPointer(), nextDataBlockSize()); + buffers.removeFirst(); + head = 0; + if (tailBuffer == 0) { + buffers << QByteArray(); + tail = 0; + } else { + --tailBuffer; + } + bufferSize -= qba.length(); + return qba; + } + + // append a new buffer to the end + inline void append(const QByteArray &qba) { + buffers[tailBuffer].resize(tail); + buffers << qba; + ++tailBuffer; + tail = qba.length(); + bufferSize += qba.length(); + } + + inline QByteArray peek(int maxLength) const { + int bytesToRead = qMin(size(), maxLength); + if (maxLength <= 0) + return QByteArray(); + QByteArray ret; + ret.resize(bytesToRead); + int readSoFar = 0; + for (int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + const int len = qMin(ret.size()-readSoFar, end-start); + memcpy(ret.data()+readSoFar, buffers.at(i).constData()+start, len); + readSoFar += len; + } + Q_ASSERT(readSoFar == ret.size()); + return ret; + } + + inline int skip(int length) { + return read(0, length); + } + + inline int readLine(char *data, int maxLength) { + int index = indexOf('\n'); + if (index == -1) + return read(data, maxLength); + if (maxLength <= 0) + return -1; + + int readSoFar = 0; + while (readSoFar < index + 1 && readSoFar < maxLength - 1) { + int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize()); + bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar); + memcpy(data + readSoFar, readPointer(), bytesToRead); + readSoFar += bytesToRead; + free(bytesToRead); + } + + // Terminate it. + data[readSoFar] = '\0'; + return readSoFar; + } + + inline bool canReadLine() const { + return indexOf('\n') != -1; + } + +private: + QList buffers; + int head, tail; + int tailBuffer; // always buffers.size() - 1 + int basicBlockSize; + int bufferSize; +}; + +QT_END_NAMESPACE + +#endif // QRINGBUFFER_P_H diff --git a/libs/serialport/qt4support/qwineventnotifier_p.h b/libs/serialport/qt4support/qwineventnotifier_p.h new file mode 100644 index 0000000000000000000000000000000000000000..bd1203e59c176bbe20fcf7e9c9ff7200354aee3b --- /dev/null +++ b/libs/serialport/qt4support/qwineventnotifier_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore 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$ +** +****************************************************************************/ + +#ifndef QWINEVENTNOTIFIER_P_H +#define QWINEVENTNOTIFIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QWinEventNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + explicit QWinEventNotifier(QObject *parent = 0); + explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); + ~QWinEventNotifier(); + + void setHandle(HANDLE hEvent); + HANDLE handle() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + +Q_SIGNALS: + void activated(HANDLE hEvent); + +protected: + bool event(QEvent * e); + +private: + Q_DISABLE_COPY(QWinEventNotifier) + + HANDLE handleToEvent; + bool enabled; +}; + +QT_END_NAMESPACE + +#endif // QWINEVENTNOTIFIER_P_H diff --git a/libs/serialport/qt4support/serialport.prf b/libs/serialport/qt4support/serialport.prf new file mode 100644 index 0000000000000000000000000000000000000000..9779b4c8224a05b0ecfc104d0a9f8af6812cd4e7 --- /dev/null +++ b/libs/serialport/qt4support/serialport.prf @@ -0,0 +1,27 @@ +qtAddLibrary(QtSerialPort) + +!isEmpty(QTSERIALPORT_BUILD_ROOT) { + INCLUDEPATH -= $$QMAKE_INCDIR_QT/QtSerialPort + QMAKE_INCDIR += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort + + QTSERIALPORT_BUILD_SUBDIR = src/serialport + debug_and_release_target { + CONFIG(debug, debug|release) { + QTSERIALPORT_BUILD_SUBDIR = $$QTSERIALPORT_BUILD_SUBDIR/debug + } else { + QTSERIALPORT_BUILD_SUBDIR = $$QTSERIALPORT_BUILD_SUBDIR/release + } + } + + QMAKE_LIBDIR += $$QTSERIALPORT_BUILD_ROOT/$$QTSERIALPORT_BUILD_SUBDIR +} + +mac { + LIBS -= -framework QtSerialPort$${QT_LIBINFIX} + + if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { + LIBS += -lQtSerialPort$${QT_LIBINFIX}_debug + } else { + LIBS += -lQtSerialPort$${QT_LIBINFIX} + } +} diff --git a/libs/serialport/qttylocker_unix.cpp b/libs/serialport/qttylocker_unix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8184bd9c035998dd912495a9adc976a28a129f76 --- /dev/null +++ b/libs/serialport/qttylocker_unix.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** 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 "qttylocker_unix_p.h" + +#ifdef HAVE_BAUDBOY_H +# include +# include +#elif defined (HAVE_LOCKDEV_H) +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined (HAVE_BAUDBOY_H) + +QT_BEGIN_NAMESPACE + +#if !(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) + +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +# define QStringLiteral QLatin1String +#endif + +static inline const QStringList& lockDirectoryList() +{ + static const QStringList lockDirectoryEntries = QStringList() + << QStringLiteral("/var/lock") + << QStringLiteral("/etc/locks") + << QStringLiteral("/var/spool/locks") + << QStringLiteral("/var/spool/uucp") + << QStringLiteral("/tmp"); + + return lockDirectoryEntries; +} + +// Returns the full path first found in the directory where you can create a lock file +// (ie a directory with access to the read/write). +// Verification of directories is of the order in accordance with the order +// of records in the variable lockDirList. +static +QString lookupFirstSharedLockDir() +{ + QStringList directoryList = lockDirectoryList(); + + foreach (const QString &lockDirectory, directoryList) { + if (::access(lockDirectory.toLocal8Bit().constData(), R_OK | W_OK) == 0) + return lockDirectory; + } + return QString(); +} + +// Returns the name of the lock file which is tied to the +// device name, eg "LCK..ttyS0", etc. +static +QString generateLockFileNameAsNamedForm(const char *portName) +{ + QString result(lookupFirstSharedLockDir()); + if (!result.isEmpty()) { + result.append(QLatin1String("/LCK..")); + result.append(QString::fromLatin1(portName).replace(QLatin1Char('/'), QLatin1Char('_'))); + } + return result; +} + +#endif //!(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) + +// Try lock serial device. However, other processes can not access it. +bool QTtyLocker::lock(const char *portName) +{ +#ifdef HAVE_BAUDBOY_H + if (::ttylock(portName) + ::ttywait(portName); + return ::ttylock(portName) != -1; +#elif defined (HAVE_LOCKDEV_H) + return ::dev_lock(portName) != -1; +#else + QFile f(generateLockFileNameAsNamedForm(portName)); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QString content(QLatin1String(" %1 %2\x0A")); + content = content.arg(::getpid()).arg(::getuid()); + if (f.write(content.toLocal8Bit()) > 0) { + f.close(); + return true; + } + f.close(); + } + return false; +#endif +} + +// Try unlock serial device. However, other processes can access it. +bool QTtyLocker::unlock(const char *portName) +{ +#ifdef HAVE_BAUDBOY_H + return ::ttyunlock(portName != -1; +#elif defined (HAVE_LOCKDEV_H) + return ::dev_unlock(portName, ::getpid()) != -1; +#else + QFile f(generateLockFileNameAsNamedForm(portName)); + return f.remove(); +#endif +} + +// Verifies the device is locked or not. +// If returned currentPid = true - this means that the device is locked the current process. +bool QTtyLocker::isLocked(const char *portName, bool *currentPid) +{ + if (!currentPid) + return true; + + *currentPid = false; + +#ifdef HAVE_BAUDBOY_H + return ::ttylocked(portName) != -1; +#elif defined (HAVE_LOCKDEV_H) + return ::dev_testlock(portName) != -1; +#else + + QFile f(generateLockFileNameAsNamedForm(portName)); + if (!f.exists()) + return false; + if (!f.open(QIODevice::ReadOnly)) + return true; + + QString content(QLatin1String(f.readAll())); + f.close(); + + const pid_t pid = content.section(' ', 0, 0, QString::SectionSkipEmpty).toInt(); + + if (::kill(pid, 0) == -1) { + if (errno == ESRCH) // Process does not exists + return false; + } else { + if (::getpid() == pid) // Process exists and it is "their", i.e current + *currentPid = true; + } + + return true; + +#endif +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qttylocker_unix_p.h b/libs/serialport/qttylocker_unix_p.h new file mode 100644 index 0000000000000000000000000000000000000000..9dce5d05dea4a1ba5da0511982273c9392c36693 --- /dev/null +++ b/libs/serialport/qttylocker_unix_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** 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 + +#ifndef TTYLOCKER_UNIX_P_H +#define TTYLOCKER_UNIX_P_H + +QT_BEGIN_NAMESPACE + +class QTtyLocker +{ +public: + static bool lock(const char *portName); + static bool unlock(const char *portName); + static bool isLocked(const char *portName, bool *currentPid); +}; + +QT_END_NAMESPACE + +#endif // TTYLOCKER_UNIX_P_H diff --git a/libs/serialport/serialport-lib.pri b/libs/serialport/serialport-lib.pri new file mode 100644 index 0000000000000000000000000000000000000000..db8ff74604c51269c8ebccd1d3c659842ad3fd81 --- /dev/null +++ b/libs/serialport/serialport-lib.pri @@ -0,0 +1,87 @@ +INCLUDEPATH += $$PWD + +unix { + CONFIG += link_pkgconfig + + packagesExist(libudev) { + DEFINES += HAVE_LIBUDEV + PKGCONFIG += libudev + } +} + +PUBLIC_HEADERS += \ + $$PWD/qserialportglobal.h \ + $$PWD/qserialport.h \ + $$PWD/qserialportinfo.h + +PRIVATE_HEADERS += \ + $$PWD/qserialport_p.h \ + $$PWD/qserialportinfo_p.h + +SOURCES += \ + $$PWD/qserialport.cpp \ + $$PWD/qserialportinfo.cpp + +win32 { + PRIVATE_HEADERS += \ + $$PWD/qserialport_win_p.h + + SOURCES += \ + $$PWD/qserialport_win.cpp \ + $$PWD/qserialportinfo_win.cpp + + !wince*: { + LIBS += -lsetupapi -ladvapi32 + } else { + SOURCES += \ + $$PWD/qserialport_wince.cpp \ + $$PWD/qserialportinfo_wince.cpp + } +} + +symbian { + MMP_RULES += EXPORTUNFROZEN + #MMP_RULES += DEBUGGABLE_UDEBONLY + TARGET.UID3 = 0xE7E62DFD + TARGET.CAPABILITY = + TARGET.EPOCALLOWDLLDATA = 1 + addFiles.sources = QtSerialPort.dll + addFiles.path = !:/sys/bin + DEPLOYMENT += addFiles + + # FIXME !!! + #INCLUDEPATH += c:/Nokia/devices/Nokia_Symbian3_SDK_v1.0/epoc32/include/platform + INCLUDEPATH += c:/QtSDK/Symbian/SDKs/Symbian3Qt473/epoc32/include/platform + + PRIVATE_HEADERS += \ + $$PWD/qserialport_symbian_p.h + + SOURCES += \ + $$PWD/qserialport_symbian.cpp \ + $$PWD/qserialportinfo_symbian.cpp + + LIBS += -leuser -lefsrv -lc32 +} + +unix:!symbian { + PRIVATE_HEADERS += \ + $$PWD/qttylocker_unix_p.h \ + $$PWD/qserialport_unix_p.h + + SOURCES += \ + $$PWD/qttylocker_unix.cpp \ + $$PWD/qserialport_unix.cpp \ + $$PWD/qserialportinfo_unix.cpp + + macx { + SOURCES += $$PWD/qserialportinfo_mac.cpp + + LIBS += -framework IOKit -framework CoreFoundation + } else { + linux*:contains( DEFINES, HAVE_LIBUDEV ) { + LIBS += -ludev + } + } +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/libs/serialport/serialport.pro b/libs/serialport/serialport.pro new file mode 100644 index 0000000000000000000000000000000000000000..d329a0b782bf0c02c14f21afc59377e35730f721 --- /dev/null +++ b/libs/serialport/serialport.pro @@ -0,0 +1,17 @@ +QT = core + +QMAKE_DOCS = $$PWD/doc/qtserialport.qdocconf +include($$PWD/serialport-lib.pri) + +greaterThan(QT_MAJOR_VERSION, 4) { + load(qt_build_config) + QT += core-private + TARGET = QtSerialPort + load(qt_module) +} else { + TEMPLATE = lib + TARGET = $$qtLibraryTarget(QtSerialPort$$QT_LIBINFIX) + include($$PWD/qt4support/install-helper.pri) + CONFIG += module create_prl + mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET +} diff --git a/qgroundcontrol.pri b/qgroundcontrol.pri index e482d65f1abe1ec257351cc37118d19cad03787c..4308af851a9a2432a27c99e5affe2f2de64cf33e 100644 --- a/qgroundcontrol.pri +++ b/qgroundcontrol.pri @@ -48,79 +48,92 @@ macx|macx-g++42|macx-g++|macx-llvm: { ICON = $$BASEDIR/files/images/icons/macx.icns # Copy contributed files - QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR/qgroundcontrol.app/Contents/MacOS + QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR/qgroundcontrol.app/Contents/MacOS # Copy google earth starter file - QMAKE_POST_LINK += && cp -f $$BASEDIR/files/images/earth.html $$TARGETDIR/qgroundcontrol.app/Contents/MacOS + QMAKE_POST_LINK += && cp -f $$BASEDIR/files/images/earth.html $$TARGETDIR/qgroundcontrol.app/Contents/MacOS # Copy CSS stylesheets QMAKE_POST_LINK += && cp -f $$BASEDIR/files/styles/style-dark.css $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/style-dark.css QMAKE_POST_LINK += && cp -f $$BASEDIR/files/styles/style-light.css $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/style-light.css # Copy support files - QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR/qgroundcontrol.app/Contents/MacOS + QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR/qgroundcontrol.app/Contents/MacOS # Copy MAVLink QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/mavlink $$TARGETDIR/qgroundcontrol.app/Contents/MacOS # Copy libraries - QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/libs - QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/lib/mac64/lib/* $$TARGETDIR/qgroundcontrol.app/Contents/libs + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/libs + QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/lib/mac64/lib/* $$TARGETDIR/qgroundcontrol.app/Contents/libs # Copy frameworks QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/Frameworks QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/lib/Frameworks/* $$TARGETDIR/qgroundcontrol.app/Contents/Frameworks +# # Copy QML stuff +message(BASEDIR $$BASEDIR) + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml + QMAKE_POST_LINK += && cp -rf $$BASEDIR/qml/*.qml $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml + + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml/components/ + QMAKE_POST_LINK += && cp -rf $$BASEDIR/qml/components/*.qml $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml/components + + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml/resources + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml/resources/qgroundcontrol + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml/resources/qgroundcontrol/toolbar + QMAKE_POST_LINK += && cp -rf $$BASEDIR/qml/resources/qgroundcontrol/toolbar/*.png $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qml/resources/qgroundcontrol/toolbar + # Fix library paths inside executable - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgWidget.dylib "@executable_path/../libs/libosgWidget.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgWidget.dylib "@executable_path/../libs/libosgWidget.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol # Fix library paths within libraries (inter-library dependencies) # OSG GA LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib # OSG DB LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib # OSG TEXT LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib # OSG UTIL LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib # OSG VIEWER LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib # OSG WIDGET LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib # CORE OSG LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosg.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosg.dylib # SDL Framework QMAKE_POST_LINK += && install_name_tool -change "@rpath/SDL.framework/Versions/A/SDL" "@executable_path/../Frameworks/SDL.framework/Versions/A/SDL" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 7d4f29eb9755bf3162043913b4760bbc82a8e39e..9814de6fe25328fed675c1b8b4c592067b200cd9 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -21,13 +21,16 @@ # Qt configuration CONFIG += qt \ thread +# serialport + QT += network \ opengl \ svg \ xml \ phonon \ webkit \ - sql + sql \ + declarative TEMPLATE = app TARGET = qgroundcontrol @@ -45,6 +48,9 @@ linux-g++|linux-g++-64{ TARGETDIR = $${OUT_PWD} BUILDDIR = $${OUT_PWD}/build } + + + LANGUAGE = C++ OBJECTS_DIR = $${BUILDDIR}/obj MOC_DIR = $${BUILDDIR}/moc @@ -93,7 +99,7 @@ DEPENDPATH += \ INCLUDEPATH += \ libs/utils \ libs \ - libs/opmapcontrol + libs/opmapcontrol \ # If the user config file exists, it will be included. # if the variable MAVLINK_CONF contains the name of an @@ -135,30 +141,23 @@ INCLUDEPATH += \ include(src/apps/mavlinkgen/mavlinkgen.pri) - - # Include QWT plotting library include(libs/qwt/qwt.pri) + DEPENDPATH += . \ - plugins \ - libs/thirdParty/qserialport/include \ - libs/thirdParty/qserialport/include/QtSerialPort \ - libs/thirdParty/qserialport \ - libs/qextserialport - -INCLUDEPATH += . \ - libs/thirdParty/qserialport/include \ - libs/thirdParty/qserialport/include/QtSerialPort \ - libs/thirdParty/qserialport/src \ - libs/qextserialport -# Include serial port library (QSerial) -include(qserialport.pri) - -# Serial port detection (ripped-off from qextserialport library) -macx|macx-g++|macx-g++42::SOURCES += libs/qextserialport/qextserialenumerator_osx.cpp -linux-g++::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp -linux-g++-64::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp -win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp + plugins + +INCLUDEPATH += . + +# Include serial port library (QSerialPort) +include(libs/serialport/qserialport.pri) + +## Serial port detection (ripped-off from qextserialport library) +#macx|macx-g++|macx-g++42::SOURCES += libs/qextserialport/qextserialenumerator_osx.cpp +#linux-g++::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp +#linux-g++-64::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp +#win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp + # Input FORMS += src/ui/MainWindow.ui \ src/ui/CommSettings.ui \ @@ -236,7 +235,34 @@ FORMS += src/ui/MainWindow.ui \ src/ui/UASRawStatusView.ui \ src/ui/uas/QGCMessageView.ui \ src/ui/JoystickButton.ui \ - src/ui/JoystickAxis.ui + src/ui/JoystickAxis.ui \ + src/ui/configuration/ApmHardwareConfig.ui \ + src/ui/configuration/ApmSoftwareConfig.ui \ + src/ui/configuration/FrameTypeConfig.ui \ + src/ui/configuration/CompassConfig.ui \ + src/ui/configuration/AccelCalibrationConfig.ui \ + src/ui/configuration/RadioCalibrationConfig.ui \ + src/ui/configuration/FlightModeConfig.ui \ + src/ui/configuration/Radio3DRConfig.ui \ + src/ui/configuration/BatteryMonitorConfig.ui \ + src/ui/configuration/SonarConfig.ui \ + src/ui/configuration/AirspeedConfig.ui \ + src/ui/configuration/OpticalFlowConfig.ui \ + src/ui/configuration/OsdConfig.ui \ + src/ui/configuration/AntennaTrackerConfig.ui \ + src/ui/configuration/CameraGimbalConfig.ui \ + src/ui/configuration/BasicPidConfig.ui \ + src/ui/configuration/StandardParamConfig.ui \ + src/ui/configuration/GeoFenceConfig.ui \ + src/ui/configuration/FailSafeConfig.ui \ + src/ui/configuration/AdvancedParamConfig.ui \ + src/ui/configuration/ArduCopterPidConfig.ui \ + src/ui/configuration/ApmPlaneLevel.ui \ + src/ui/configuration/ParamWidget.ui \ + src/ui/configuration/ArduPlanePidConfig.ui \ + src/ui/configuration/AdvParameterList.ui \ + src/ui/configuration/ArduRoverPidConfig.ui + INCLUDEPATH += src \ src/ui \ src/ui/linechart \ @@ -252,7 +278,8 @@ INCLUDEPATH += src \ src/ui/watchdog \ src/ui/map3D \ src/ui/mission \ - src/ui/designer + src/ui/designer \ + src/ui/configuration HEADERS += src/MG.h \ src/QGCCore.h \ src/uas/UASInterface.h \ @@ -346,7 +373,7 @@ HEADERS += src/MG.h \ src/ui/map/Waypoint2DIcon.h \ src/ui/map/QGCMapTool.h \ src/ui/map/QGCMapToolBar.h \ - libs/qextserialport/qextserialenumerator.h \ +# libs/qextserialport/qextserialenumerator.h \ src/QGCGeo.h \ src/ui/QGCToolBar.h \ src/ui/QGCStatusBar.h \ @@ -396,7 +423,35 @@ HEADERS += src/MG.h \ src/ui/PrimaryFlightDisplay.h \ src/ui/uas/QGCMessageView.h \ src/ui/JoystickButton.h \ - src/ui/JoystickAxis.h + src/ui/JoystickAxis.h \ + src/ui/configuration/ApmHardwareConfig.h \ + src/ui/configuration/ApmSoftwareConfig.h \ + src/ui/configuration/FrameTypeConfig.h \ + src/ui/configuration/CompassConfig.h \ + src/ui/configuration/AccelCalibrationConfig.h \ + src/ui/configuration/RadioCalibrationConfig.h \ + src/ui/configuration/FlightModeConfig.h \ + src/ui/configuration/Radio3DRConfig.h \ + src/ui/configuration/BatteryMonitorConfig.h \ + src/ui/configuration/SonarConfig.h \ + src/ui/configuration/AirspeedConfig.h \ + src/ui/configuration/OpticalFlowConfig.h \ + src/ui/configuration/OsdConfig.h \ + src/ui/configuration/AntennaTrackerConfig.h \ + src/ui/configuration/CameraGimbalConfig.h \ + src/ui/configuration/AP2ConfigWidget.h \ + src/ui/configuration/BasicPidConfig.h \ + src/ui/configuration/StandardParamConfig.h \ + src/ui/configuration/GeoFenceConfig.h \ + src/ui/configuration/FailSafeConfig.h \ + src/ui/configuration/AdvancedParamConfig.h \ + src/ui/configuration/ArduCopterPidConfig.h \ + src/ui/apmtoolbar.h \ + src/ui/configuration/ApmPlaneLevel.h \ + src/ui/configuration/ParamWidget.h \ + src/ui/configuration/ArduPlanePidConfig.h \ + src/ui/configuration/AdvParameterList.h \ + src/ui/configuration/ArduRoverPidConfig.h # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::HEADERS += src/ui/map3D/QGCGoogleEarthView.h @@ -572,9 +627,37 @@ SOURCES += src/main.cc \ src/ui/QGCTabbedInfoView.cpp \ src/ui/UASRawStatusView.cpp \ src/ui/PrimaryFlightDisplay.cc \ - src/ui/uas/QGCMessageView.cc \ src/ui/JoystickButton.cc \ - src/ui/JoystickAxis.cc + src/ui/JoystickAxis.cc \ + src/ui/uas/QGCMessageView.cc \ + src/ui/configuration/ApmHardwareConfig.cc \ + src/ui/configuration/ApmSoftwareConfig.cc \ + src/ui/configuration/FrameTypeConfig.cc \ + src/ui/configuration/CompassConfig.cc \ + src/ui/configuration/AccelCalibrationConfig.cc \ + src/ui/configuration/RadioCalibrationConfig.cc \ + src/ui/configuration/FlightModeConfig.cc \ + src/ui/configuration/Radio3DRConfig.cc \ + src/ui/configuration/BatteryMonitorConfig.cc \ + src/ui/configuration/SonarConfig.cc \ + src/ui/configuration/AirspeedConfig.cc \ + src/ui/configuration/OpticalFlowConfig.cc \ + src/ui/configuration/OsdConfig.cc \ + src/ui/configuration/AntennaTrackerConfig.cc \ + src/ui/configuration/CameraGimbalConfig.cc \ + src/ui/configuration/AP2ConfigWidget.cc \ + src/ui/configuration/BasicPidConfig.cc \ + src/ui/configuration/StandardParamConfig.cc \ + src/ui/configuration/GeoFenceConfig.cc \ + src/ui/configuration/FailSafeConfig.cc \ + src/ui/configuration/AdvancedParamConfig.cc \ + src/ui/configuration/ArduCopterPidConfig.cc \ + src/ui/apmtoolbar.cpp \ + src/ui/configuration/ApmPlaneLevel.cc \ + src/ui/configuration/ParamWidget.cc \ + src/ui/configuration/ArduPlanePidConfig.cc \ + src/ui/configuration/AdvParameterList.cc \ + src/ui/configuration/ArduRoverPidConfig.cc # Enable Google Earth only on Mac OS and Windows with Visual Studio compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += src/ui/map3D/QGCGoogleEarthView.cc @@ -710,4 +793,31 @@ unix:!macx:!symbian: LIBS += -losg OTHER_FILES += \ dongfang_notes.txt \ - src/ui/dongfang-scrapyard.txt + src/ui/dongfang-scrapyard.txt \ + qml/components/DigitalDisplay.qml + +OTHER_FILES += \ + qml/ApmToolBar.qml \ + qml/components/Button.qml \ + qml/components/TextButton.qml \ + qml/resources/qgroundcontrol/toolbar/connect.png \ + qml/resources/qgroundcontrol/toolbar/flightplanner.png \ + qml/resources/qgroundcontrol/toolbar/helpwizard.png \ + qml/resources/qgroundcontrol/toolbar/softwareconfig.png \ + qml/resources/qgroundcontrol/toolbar/terminal.png \ + qml/resources/qgroundcontrol/toolbar/simulation.png \ + qml/resources/qgroundcontrol/toolbar/hardwareconfig.png \ + qml/resources/qgroundcontrol/toolbar/flightdata.png \ + qml/resources/qgroundcontrol/toolbar/disconnect.png \ + qml/resources/qgroundcontrol/toolbar/donate.png \ + + +#qmlcomponents.path += $${DESTDIR}$${TARGET}/components +#qmlcomponents.files += ./components/Button.qml + +#sources.files += ApmToolBar.qml +#sources.path += $$DESTDIR/qml +#target.path += qgroundcontrol +#INSTALLS += sources target + +message( BASEDIR $$BASEDIR DESTDIR $$DESTDIR TARGET $$TARGET TARGETDIR $$TARGETDIR) diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 1323ec395e2857d97670657cc0ad138b7b22829a..25152d21ad07f20469b88cb9cd45bf80bfadb813 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -102,6 +102,23 @@ files/images/patterns/lenna.jpg files/images/rc_stick.svg files/images/actions/qgroundcontrol-connect.svg + files/images/apm_planner_logo.png + files/images/apm_planner_logo_splash.png + files/images/apm_planner_2_0-07.png + files/images/apm_planner_2_0-08.png + files/images/mavs/frames_plus.png + files/images/mavs/frames_x.png + files/images/mavs/frames-05.png + files/images/devices/BR-HMC5883-01-2.jpg + files/images/devices/BR-APMPWRDEAN-2.jpg + files/images/devices/AC-0004-11-2.jpg + files/images/devices/BR-0004-03-2.jpg + files/images/devices/BR-0016-01-3T.jpg + files/images/devices/MinimOSD.jpg + files/images/devices/cameraGimalPitch1.png + files/images/devices/cameraGimalRoll1.png + files/images/devices/cameraGimalYaw.png + files/images/devices/Shutter.png files/styles/Vera.ttf diff --git a/qml/ApmToolBar.qml b/qml/ApmToolBar.qml new file mode 100644 index 0000000000000000000000000000000000000000..154ee94b870f6b05bf42bec06888007b64027122 --- /dev/null +++ b/qml/ApmToolBar.qml @@ -0,0 +1,181 @@ +import QtQuick 1.1 +import "./components" + + +Rectangle { + id: toolbar + + property alias backgroundColor : toolbar.color + property alias linkNameLabel: linkDevice.label + property alias baudrateLabel: baudrate.label + property bool connected: false + + width: toolbar.width + height: 72 + color: "black" + border.color: "black" + + onConnectedChanged: { + if (connected){ + console.log("APM Tool BAR QML: connected") + connectButton.image = "./resources/qgroundcontrol/toolbar/disconnect.png" + connectButton.label = "DISCONNECT" + } else { + console.log("APM Tool BAR QML: disconnected") + connectButton.image = "./resources/qgroundcontrol/toolbar/connect.png" + connectButton.label = "CONNECT" + } + } + +// [BB] The code below should work, not sure why. replaced with code above +// Connections { +// target: globalObj +// onMAVConnected: { +// console.log("QML Change Connection " + connected) +// if (connected){ +// console.log("connected") +// connectButton.image = "./resources/qgroundcontrol/toolbar/disconnect.png" +// } else { +// console.log("disconnected") +// connectButton.image = "./resources/qgroundcontrol/toolbar/connect.png" +// } +// } +// } + + Row { + anchors.left: parent.left + spacing: 2 + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + + Button { + id: flightDataView + label: "FLIGHT DATA" + image: "./resources/qgroundcontrol/toolbar/flightdata.png" + onClicked: { + globalObj.triggerFlightView() + } + } + + Button { + id: flightPlanView + label: "FLIGHT PLAN" + image: "./resources/qgroundcontrol/toolbar/flightplanner.png" + onClicked: globalObj.triggerFlightPlanView() + } + + Button { + id: hardwareConfigView + label: "HARDWARE" + image: "./resources/qgroundcontrol/toolbar/hardwareconfig.png" + margins: 8 + onClicked: globalObj.triggerHardwareView() + } + + Button { + id: softwareConfigView + label: "SOFTWARE" + image: "./resources/qgroundcontrol/toolbar/softwareconfig.png" + margins: 8 + onClicked: globalObj.triggerSoftwareView() + } + + Button { + id: simulationView + label: "SIMULATION" + image: "./resources/qgroundcontrol/toolbar/simulation.png" + onClicked: globalObj.triggerSimulationView() + } + + Button { + id: terminalView + label: "TERMINAL" + image: "./resources/qgroundcontrol/toolbar/terminal.png" + onClicked: globalObj.triggerTerminalView() + } + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + +// [BB] Commented out ToolBar Status info work. +// WIP: To be fixed later +// DigitalDisplay { // Information Pane +// title:"Mode" +// textValue: "Stabilize" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Speed" +// textValue: "11.0m/s" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Alt" +// textValue: "20.0m" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Volts" +// textValue: "14.8V" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Current" +// textValue: "12.0A" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Level" +// textValue: "77%" +// color: "black" +// } + + } + + Row { + anchors.right: parent.right + spacing: 2 + + TextButton { + id: linkDevice + label: "none" + minWidth: 100 + + onClicked: globalObj.showConnectionDialog() + } + + TextButton { + id: baudrate + label: "none" + minWidth: 100 + + onClicked: globalObj.showConnectionDialog() + } + + Rectangle { + width: 5 + height: parent.height + color: "black" + } + + Button { + id: connectButton + label: "CONNECT" + image: "./resources/qgroundcontrol/toolbar/connect.png" + onClicked: globalObj.connectMAV() + } + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + } +} diff --git a/qml/components/Button.qml b/qml/components/Button.qml new file mode 100644 index 0000000000000000000000000000000000000000..798a161076bb015a7845c7ac3254e2c4e7a8e9d8 --- /dev/null +++ b/qml/components/Button.qml @@ -0,0 +1,70 @@ +import QtQuick 1.1 + +Rectangle { + signal clicked + + property string label: "button label" + property alias image: buttonImage.source + property int margins: 2 + + id: button + width: 72 + height: 72 + radius: 3 + smooth: true + border.width: 2 + + Text { + id: buttonLabel + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 5 + text: label + color: "white" + font.pointSize: 10 + } + + Image { + id: buttonImage + anchors.horizontalCenter: button.horizontalCenter + anchors.top: buttonLabel.bottom + anchors.margins: margins + source: image + fillMode: Image.PreserveAspectFit + width: image.width + height: image.height + } + + signal buttonClick() + + onButtonClick: { + console.log(buttonLabel.text + " clicked calling signal") + clicked() + } + + // Highlighting and ativation section + property color buttonColor: "black" + property color onHoverbuttonColor: "lightblue" + property color onHoverColor: "darkblue" + property color borderColor: "black" + + MouseArea { + id: buttonMouseArea + anchors.fill: parent + onClicked: buttonClick() + hoverEnabled: true + onEntered: { + parent.border.color = onHoverColor + parent.color = onHoverbuttonColor + } + onExited: { + parent.border.color = borderColor + parent.color = buttonColor + } + onPressed: parent.color = Qt.darker(onHoverbuttonColor, 1.5) + onReleased: parent.color = buttonColor + } + color: buttonColor + border.color: borderColor +} + diff --git a/qml/components/DigitalDisplay.qml b/qml/components/DigitalDisplay.qml new file mode 100644 index 0000000000000000000000000000000000000000..be69b6712bdf2033e376100ae256e059ffd8756b --- /dev/null +++ b/qml/components/DigitalDisplay.qml @@ -0,0 +1,30 @@ +import QtQuick 1.1 + +Rectangle { + + property alias title: displayTitle.text + property string textValue: "none" + + width: 100 + height: parent.height/3 + anchors.verticalCenter: parent.verticalCenter + border.color: "white" + + Text { + id:displayTitle + anchors.left: parent.left + anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + text: "blank" + color: "white" + } + + Text { + id:displayValue + anchors.right: parent.right + anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + text: textValue + color: "white" + } +} diff --git a/qml/components/TextButton.qml b/qml/components/TextButton.qml new file mode 100644 index 0000000000000000000000000000000000000000..c7b2b32226103c85779769e3af60df0cda11ab68 --- /dev/null +++ b/qml/components/TextButton.qml @@ -0,0 +1,70 @@ +import QtQuick 1.1 + +Rectangle { + signal clicked + + property string label: "Text Button label" + property int minWidth: 75 + property int minHeight: 0 + property int margin: 5 + + width: textBox.width + height: 72 + anchors.verticalCenter: parent.verticalCenter + color: "black" + + signal buttonClick() + + onButtonClick: { + console.log(label + " clicked calling signal") + clicked() + } + + // Highlighting and ativation section + property color buttonColor: "black" + property color onHoverbuttonColor: "lightblue" + property color onHoverColor: "darkblue" + property color borderColor: "white" + + Rectangle { + width: textButtonLabel.paintedwidth + anchors.centerIn: parent + + Rectangle{ + id: textBox + anchors.centerIn: parent + width: minWidth > textButtonLabel.paintedWidth + margin ? minWidth : textButtonLabel.paintedWidth + margin + height: minHeight > textButtonLabel.paintedHeight + margin ? minHeight : textButtonLabel.paintedHeight + margin + + Text { + id: textButtonLabel + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 2 + text: label + color: "white" + font.pointSize: 11 + } + + MouseArea { + id: textButtonMouseArea + anchors.fill: parent + onClicked: buttonClick() + hoverEnabled: true + onEntered: { + parent.border.color = onHoverColor + parent.color = onHoverbuttonColor + } + onExited: { + parent.border.color = borderColor + parent.color = buttonColor + } + onPressed: parent.color = Qt.darker(onHoverbuttonColor, 1.5) + onReleased: parent.color = buttonColor + } + color: buttonColor + border.color: borderColor + border.width: 1 + } + } +} diff --git a/src/QGCCore.cc b/src/QGCCore.cc index d58f07f5c964e95b06d55c4ec33ee3927be64f9e..8aae8771fbf3bee83e37961081bf79e912b95289 100644 --- a/src/QGCCore.cc +++ b/src/QGCCore.cc @@ -52,6 +52,7 @@ This file is part of the QGROUNDCONTROL project #endif #include "UDPLink.h" #include "MAVLinkSimulationLink.h" +#include "SerialLink.h" /** @@ -70,8 +71,8 @@ QGCCore::QGCCore(int &argc, char* argv[]) : QApplication(argc, argv) // Set application name this->setApplicationName(QGC_APPLICATION_NAME); this->setApplicationVersion(QGC_APPLICATION_VERSION); - this->setOrganizationName(QLatin1String("QGroundControl")); - this->setOrganizationDomain("org.qgroundcontrol"); + this->setOrganizationName(QLatin1String("diydrones")); + this->setOrganizationDomain("com.diydrones"); // Set settings format QSettings::setDefaultFormat(QSettings::IniFormat); @@ -156,41 +157,18 @@ QGCCore::QGCCore(int &argc, char* argv[]) : QApplication(argc, argv) MAVLinkSimulationLink* simulationLink = new MAVLinkSimulationLink(":/demo-log.txt"); simulationLink->disconnect(); - // Remove splash screen - splashScreen->finish(mainWindow); + //We want to have a default serial link available for "quick" connecting. + SerialLink *slink = new SerialLink(); + MainWindow::instance()->addLink(slink); - if (upgraded) mainWindow->showInfoMessage(tr("Default Settings Loaded"), tr("QGroundControl has been upgraded from version %1 to version %2. Some of your user preferences have been reset to defaults for safety reasons. Please adjust them where needed.").arg(lastApplicationVersion).arg(QGC_APPLICATION_VERSION)); + mainWindow = MainWindow::instance(splashScreen); - // Check if link could be connected - if (!udpLink->connect()) - { - QMessageBox msgBox; - msgBox.setIcon(QMessageBox::Critical); - msgBox.setText("Could not connect UDP port. Is an instance of " + qAppName() + "already running?"); - msgBox.setInformativeText("You will not be able to receive data via UDP. Please check that you're running the right executable and then re-start " + qAppName() + ". Do you want to close the application?"); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::No); - int ret = msgBox.exec(); - - // Close the message box shortly after the click to prevent accidental clicks - QTimer::singleShot(15000, &msgBox, SLOT(reject())); - - // Exit application - if (ret == QMessageBox::Yes) - { - //mainWindow->close(); - QTimer::singleShot(200, mainWindow, SLOT(close())); - } - } + // Remove splash screen + splashScreen->finish(mainWindow); -// forever -// { -// QGC::SLEEP::msleep(5000); -// } + if (upgraded) mainWindow->showInfoMessage(tr("Default Settings Loaded"), + tr("qgroundcontrol has been upgraded from version %1 to version %2. Some of your user preferences have been reset to defaults for safety reasons. Please adjust them where needed.").arg(lastApplicationVersion).arg(QGC_APPLICATION_VERSION)); -// mainWindow->close(); -// mainWindow->deleteLater(); -// QGC::SLEEP::msleep(200); } /** diff --git a/src/comm/LinkInterface.h b/src/comm/LinkInterface.h index 9d62a6c77c4e4ef8c52f241f1af8cc6cb3bc827b..9ecf75ac1d537ae2f1458e246bd19c422f413c72 100644 --- a/src/comm/LinkInterface.h +++ b/src/comm/LinkInterface.h @@ -61,6 +61,8 @@ public: */ virtual QString getName() const = 0; + virtual void requestReset() = 0; + /** * @brief Determine the connection status * diff --git a/src/comm/MAVLinkProtocol.cc b/src/comm/MAVLinkProtocol.cc index 4941c68a948d902830e3ef56d3658e46339e6c45..8684e0a6687ee516b42e7e306c89c1af4c1f4997 100644 --- a/src/comm/MAVLinkProtocol.cc +++ b/src/comm/MAVLinkProtocol.cc @@ -198,7 +198,7 @@ void MAVLinkProtocol::linkStatusChanged(bool connected) link->writeBytes(init, sizeof(init)); // Stop any running mavlink instance - char* cmd = "mavlink stop\n"; + const char* cmd = "mavlink stop\n"; link->writeBytes(cmd, strlen(cmd)); link->writeBytes(init, 2); cmd = "uorb start"; @@ -228,8 +228,11 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) int linkId = link->getId(); static int mavlink09Count = 0; + static int nonmavlinkCount = 0; static bool decodedFirstPacket = false; static bool warnedUser = false; + static bool checkedUserNonMavlink = false; + static bool warnedUserNonMavlink = false; // FIXME: Add check for if link->getId() >= MAVLINK_COMM_NUM_BUFFERS for (int position = 0; position < b.size(); position++) { @@ -244,9 +247,24 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) emit protocolStatusMessage("MAVLink Version or Baud Rate Mismatch", "Your MAVLink device seems to use the deprecated version 0.9, while QGroundControl only supports version 1.0+. Please upgrade the MAVLink version of your autopilot. If your autopilot is using version 1.0, check if the baud rates of QGroundControl and your autopilot are the same."); } - // Count parser errors as well. - totalErrorCounter[linkId] += status.packet_rx_drop_count; - + if (decodeState == 0 && !decodedFirstPacket) + { + nonmavlinkCount++; + if (nonmavlinkCount > 500 && !warnedUserNonMavlink) + { + //500 bytes with no mavlink message. Are we connected to a mavlink capable device? + if (!checkedUserNonMavlink) + { + link->requestReset(); + checkedUserNonMavlink = true; + } + else + { + warnedUserNonMavlink = true; + emit protocolStatusMessage("MAVLink Baud Rate Mismatch", "Please check if the baud rates of QGroundControl and your autopilot are the same."); + } + } + } if (decodeState == 1) { decodedFirstPacket = true; diff --git a/src/comm/MAVLinkSimulationLink.h b/src/comm/MAVLinkSimulationLink.h index 505a9012f77a2f03ecc10d35b79ba01090d889ee..f5befb91fc5fbd6e4d2a363cc2dd8546a0e4dc3e 100644 --- a/src/comm/MAVLinkSimulationLink.h +++ b/src/comm/MAVLinkSimulationLink.h @@ -54,7 +54,7 @@ public: qint64 bytesAvailable(); void run(); - + void requestReset() { } bool connect(); bool disconnect(); diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc index 60a4ba568ad77eb850d49799f932a8a92376b357..f583482e9895598cd1695c799ffed1f3d8a8a59c 100644 --- a/src/comm/SerialLink.cc +++ b/src/comm/SerialLink.cc @@ -12,348 +12,103 @@ #include #include #include +#include +#include #include "SerialLink.h" #include "LinkManager.h" #include "QGC.h" #include -#include -#ifdef _WIN32 -#include "windows.h" -#endif -#ifdef _WIN32 -#include -#endif -#if defined (__APPLE__) && defined (__MACH__) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __MWERKS__ -#define __CF_USE_FRAMEWORK_INCLUDES__ -#endif - - -#include - -#include -#include -#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3) -#include -#endif -#include - -// Apple internal modems default to local echo being on. If your modem has local echo disabled, -// undefine the following macro. -#define LOCAL_ECHO - -#define kATCommandString "AT\r" - -#ifdef LOCAL_ECHO -#define kOKResponseString "AT\r\r\nOK\r\n" -#else -#define kOKResponseString "\r\nOK\r\n" -#endif -#endif - - -// Some helper functions for serial port enumeration -#if defined (__APPLE__) && defined (__MACH__) - -enum { - kNumRetries = 3 -}; - -// Function prototypes -static kern_return_t FindModems(io_iterator_t *matchingServices); -static kern_return_t GetModemPath(io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize); - -// Returns an iterator across all known modems. Caller is responsible for -// releasing the iterator when iteration is complete. -static kern_return_t FindModems(io_iterator_t *matchingServices) -{ - kern_return_t kernResult; - CFMutableDictionaryRef classesToMatch; - - /*! @function IOServiceMatching - @abstract Create a matching dictionary that specifies an IOService class match. - @discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name. - @param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass. - @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ - - // Serial devices are instances of class IOSerialBSDClient - classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); - if (classesToMatch == NULL) { - printf("IOServiceMatching returned a NULL dictionary.\n"); - } else { - /*! - @function CFDictionarySetValue - Sets the value of the key in the dictionary. - @param theDict The dictionary to which the value is to be set. If this - parameter is not a valid mutable CFDictionary, the behavior is - undefined. If the dictionary is a fixed-capacity dictionary and - it is full before this operation, and the key does not exist in - the dictionary, the behavior is undefined. - @param key The key of the value to set into the dictionary. If a key - which matches this key is already present in the dictionary, only - the value is changed ("add if absent, replace if present"). If - no key matches the given key, the key-value pair is added to the - dictionary. If added, the key is retained by the dictionary, - using the retain callback provided - when the dictionary was created. If the key is not of the sort - expected by the key retain callback, the behavior is undefined. - @param value The value to add to or replace into the dictionary. The value - is retained by the dictionary using the retain callback provided - when the dictionary was created, and the previous value if any is - released. If the value is not of the sort expected by the - retain or release callbacks, the behavior is undefined. - */ - CFDictionarySetValue(classesToMatch, - CFSTR(kIOSerialBSDTypeKey), - CFSTR(kIOSerialBSDModemType)); - - // Each serial device object has a property with key - // kIOSerialBSDTypeKey and a value that is one of kIOSerialBSDAllTypes, - // kIOSerialBSDModemType, or kIOSerialBSDRS232Type. You can experiment with the - // matching by changing the last parameter in the above call to CFDictionarySetValue. - - // As shipped, this sample is only interested in modems, - // so add this property to the CFDictionary we're matching on. - // This will find devices that advertise themselves as modems, - // such as built-in and USB modems. However, this match won't find serial modems. - } - - /*! @function IOServiceGetMatchingServices - @abstract Look up registered IOService objects that match a matching dictionary. - @discussion This is the preferred method of finding IOService objects currently registered by IOKit. IOServiceAddNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up. - @param masterPort The master port obtained from IOMasterPort(). - @param matching A CF dictionary containing matching information, of which one reference is consumed by this function. IOKitLib can contruct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOOpenFirmwarePathMatching. - @param existing An iterator handle is returned on success, and should be released by the caller when the iteration is finished. - @result A kern_return_t error code. */ - - kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, matchingServices); - if (KERN_SUCCESS != kernResult) { - printf("IOServiceGetMatchingServices returned %d\n", kernResult); - goto exit; - } - -exit: - return kernResult; -} - -/** Given an iterator across a set of modems, return the BSD path to the first one. - * If no modems are found the path name is set to an empty string. - */ -static kern_return_t GetModemPath(io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize) -{ - io_object_t modemService; - kern_return_t kernResult = KERN_FAILURE; - Boolean modemFound = false; - - // Initialize the returned path - *bsdPath = '\0'; - - // Iterate across all modems found. In this example, we bail after finding the first modem. - - while ((modemService = IOIteratorNext(serialPortIterator)) && !modemFound) { - CFTypeRef bsdPathAsCFString; - - // Get the callout device's path (/dev/cu.xxxxx). The callout device should almost always be - // used: the dialin device (/dev/tty.xxxxx) would be used when monitoring a serial port for - // incoming calls, e.g. a fax listener. - - bsdPathAsCFString = IORegistryEntryCreateCFProperty(modemService, - CFSTR(kIOCalloutDeviceKey), - kCFAllocatorDefault, - 0); - if (bsdPathAsCFString) { - Boolean result; - - // Convert the path from a CFString to a C (NUL-terminated) string for use - // with the POSIX open() call. - - result = CFStringGetCString((CFStringRef)bsdPathAsCFString, - bsdPath, - maxPathSize, - kCFStringEncodingUTF8); - CFRelease(bsdPathAsCFString); - - if (result) { - //printf("Modem found with BSD path: %s", bsdPath); - modemFound = true; - kernResult = KERN_SUCCESS; - } - } - - printf("\n"); - - // Release the io_service_t now that we are done with it. - - (void) IOObjectRelease(modemService); - } - - return kernResult; -} -#endif - -using namespace TNX; SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity, int dataBits, int stopBits) : - port(NULL), - ports(new QVector()), + m_bytesRead(0), + m_port(NULL), m_stopp(false), - bytesRead(0) + m_reqReset(false) { + qDebug() << "create SerialLink " << portname << baudRate << hardwareFlowControl + << parity << dataBits << stopBits; // Setup settings - this->porthandle = portname.trimmed(); + m_portName = portname.trimmed(); - if (this->porthandle == "" && getCurrentPorts()->size() > 0) + if (m_portName == "" && getCurrentPorts().size() > 0) { - this->porthandle = getCurrentPorts()->first().trimmed(); + m_portName = m_ports.first().trimmed(); } -#ifdef _WIN32 - // Port names above 20 need the network path format - if the port name is not already in this format - // catch this special case - if (this->porthandle.size() > 0 && !this->porthandle.startsWith("\\")) { - // Append \\.\ before the port handle. Additional backslashes are used for escaping. - this->porthandle = "\\\\.\\" + this->porthandle; - } -#endif + qDebug() << "m_portName " << m_portName; + // Set unique ID and add link to the list of links - this->id = getNextLinkId(); + m_id = getNextLinkId(); + + m_baud = baudRate; - setBaudRate(baudRate); if (hardwareFlowControl) { - portSettings.setFlowControl(QPortSettings::FLOW_HARDWARE); + m_flowControl = QSerialPort::HardwareControl; } else { - portSettings.setFlowControl(QPortSettings::FLOW_OFF); + m_flowControl = QSerialPort::NoFlowControl; } if (parity) { - portSettings.setParity(QPortSettings::PAR_EVEN); + m_parity = QSerialPort::EvenParity; } else { - portSettings.setParity(QPortSettings::PAR_NONE); + m_parity = QSerialPort::NoParity; } - setDataBits(dataBits); - setStopBits(stopBits); + + m_dataBits = dataBits; + m_stopBits = stopBits; // Set the port name - if (porthandle == "") - { - name = tr("Serial Link ") + QString::number(getId()); - } - else - { - name = portname.trimmed(); - } +// if (m_portName == "") +// { +// m_name = tr("Serial Link ") + QString::number(getId()); +// } +// else +// { +// m_name = portname.trimmed(); +// } + loadSettings(); } +void SerialLink::requestReset() +{ + QMutexLocker locker(&this->m_stoppMutex); + m_reqReset = true; +} SerialLink::~SerialLink() { disconnect(); - if(port) delete port; - port = NULL; - if (ports) delete ports; - ports = NULL; + if(m_port) delete m_port; + m_port = NULL; } -QVector* SerialLink::getCurrentPorts() +QList SerialLink::getCurrentPorts() { - ports->clear(); -#ifdef __linux - - // TODO Linux has no standard way of enumerating serial ports - // However the device files are only present when the physical - // device is connected, therefore listing the files should be - // sufficient. - - QString devdir = "/dev"; - QDir dir(devdir); - dir.setFilter(QDir::System); - - QFileInfoList list = dir.entryInfoList(); - for (int i = 0; i < list.size(); ++i) { - QFileInfo fileInfo = list.at(i); - if (fileInfo.fileName().contains(QString("ttyUSB")) || fileInfo.fileName().contains(QString("ttyS")) || fileInfo.fileName().contains(QString("ttyACM"))) - { - ports->append(fileInfo.canonicalFilePath()); - } - } -#endif - -#if defined (__APPLE__) && defined (__MACH__) + m_ports.clear(); + // Example use QSerialPortInfo + // [TODO] make this thread safe - // Enumerate serial ports - kern_return_t kernResult; // on PowerPC this is an int (4 bytes) - io_iterator_t serialPortIterator; - char bsdPath[MAXPATHLEN]; - kernResult = FindModems(&serialPortIterator); - kernResult = GetModemPath(serialPortIterator, bsdPath, sizeof(bsdPath)); - IOObjectRelease(serialPortIterator); // Release the iterator. + QList portList = QSerialPortInfo::availablePorts(); - // Add found modems - if (bsdPath[0]) - { - ports->append(QString(bsdPath)); + if( portList.count() == 0){ + qDebug() << "No Ports Found" << m_ports; } - // Add USB serial port adapters - // TODO Strangely usb serial port adapters are not enumerated, even when connected - QString devdir = "/dev"; - QDir dir(devdir); - dir.setFilter(QDir::System); - - QFileInfoList list = dir.entryInfoList(); - for (int i = list.size() - 1; i >= 0; i--) { - QFileInfo fileInfo = list.at(i); - if (fileInfo.fileName().contains(QString("ttyUSB")) || - fileInfo.fileName().contains(QString("tty.")) || - fileInfo.fileName().contains(QString("ttyS")) || - fileInfo.fileName().contains(QString("ttyACM"))) - { - ports->append(fileInfo.canonicalFilePath()); - } - } -#endif - -#ifdef _WIN32 - // Get the ports available on this system - QList ports = QextSerialEnumerator::getPorts(); - - // Add the ports in reverse order, because we prepend them to the list - for (int i = ports.size() - 1; i >= 0; i--) + foreach (const QSerialPortInfo &info, portList) { - QextPortInfo portInfo = ports.at(i); - QString portString = QString(portInfo.portName.toLocal8Bit().constData()) + " - " + QString(ports.at(i).friendName.toLocal8Bit().constData()).split("(").first(); - // Prepend newly found port to the list - this->ports->append(portString); - } +// qDebug() << "PortName : " << info.portName() +// << "Description : " << info.description(); +// qDebug() << "Manufacturer: " << info.manufacturer(); - //printf("port name: %s\n", ports.at(i).portName.toLocal8Bit().constData()); - //printf("friendly name: %s\n", ports.at(i).friendName.toLocal8Bit().constData()); - //printf("physical name: %s\n", ports.at(i).physName.toLocal8Bit().constData()); - //printf("enumerator name: %s\n", ports.at(i).enumName.toLocal8Bit().constData()); - //printf("===================================\n\n"); -#endif - return this->ports; + m_ports.append(info.portName()); + } + return m_ports; } void SerialLink::loadSettings() @@ -363,12 +118,12 @@ void SerialLink::loadSettings() settings.sync(); if (settings.contains("SERIALLINK_COMM_PORT")) { - setPortName(settings.value("SERIALLINK_COMM_PORT").toString()); - setBaudRateType(settings.value("SERIALLINK_COMM_BAUD").toInt()); - setParityType(settings.value("SERIALLINK_COMM_PARITY").toInt()); - setStopBits(settings.value("SERIALLINK_COMM_STOPBITS").toInt()); - setDataBits(settings.value("SERIALLINK_COMM_DATABITS").toInt()); - setFlowType(settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt()); + m_portName = settings.value("SERIALLINK_COMM_PORT").toString(); + m_baud = settings.value("SERIALLINK_COMM_BAUD").toInt(); + m_parity = settings.value("SERIALLINK_COMM_PARITY").toInt(); + m_stopBits = settings.value("SERIALLINK_COMM_STOPBITS").toInt(); + m_dataBits = settings.value("SERIALLINK_COMM_DATABITS").toInt(); + m_flowControl = settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt(); } } @@ -396,33 +151,69 @@ void SerialLink::run() if (!hardwareConnect()) { //Need to error out here. - emit communicationError(getName(),"Error connecting: " + port->errorString()); + emit communicationError(getName(),"Error connecting: " + m_port->errorString()); return; - } // Qt way to make clear what a while(1) loop does - quint64 msecs = QDateTime::currentMSecsSinceEpoch(); - quint64 initialmsecs = QDateTime::currentMSecsSinceEpoch(); + qint64 msecs = QDateTime::currentMSecsSinceEpoch(); + qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch(); quint64 bytes = 0; bool triedreset = false; bool triedDTR = false; - int timeout = 5000; + qint64 timeout = 5000; + forever { { QMutexLocker locker(&this->m_stoppMutex); - if(this->m_stopp) + if(m_stopp) { - this->m_stopp = false; - break; + m_stopp = false; + break; // exit the thread + } + + if (m_reqReset) + { + m_reqReset = false; + communicationUpdate(getName(),"Reset requested via DTR signal"); + m_port->setDataTerminalReady(true); + msleep(250); + m_port->setDataTerminalReady(false); } } - // Check if new bytes have arrived, if yes, emit the notification signal - checkForBytes(); - if (bytes != bytesRead) + + if (m_transmitBuffer.size() > 0) { + // send the data + QMutexLocker lockWrite(&m_writeMutex); + int num_written = m_port->write(m_transmitBuffer.constData()); + if (num_written > 0){ + m_transmitBuffer = m_transmitBuffer.remove(0,num_written); + } + + } + + + bool error = m_port->waitForReadyRead(500); + + if(error) { // Waits for 1/2 second [TODO][BB] lower to SerialLink::poll_interval? + QByteArray readData = m_port->readAll(); + while (m_port->waitForReadyRead(10)) + readData += m_port->readAll(); + if (readData.length() > 0) { + emit bytesReceived(this, readData); +// qDebug() << "rx of length " << QString::number(readData.length()); + + m_bytesRead += readData.length(); + m_bitsReceivedTotal += readData.length() * 8; + } + } else { +// qDebug() << "readyReadTime #"<< __LINE__; + + } + if (bytes != m_bytesRead) // i.e things are good and data is being read. { - bytes = bytesRead; + bytes = m_bytesRead; msecs = QDateTime::currentMSecsSinceEpoch(); } else @@ -445,15 +236,15 @@ void SerialLink::run() triedDTR = true; communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal"); qDebug() << "No data!!! Attempting reset via DTR."; - port->setDtr(true); - this->msleep(250); - port->setDtr(false); + m_port->setDataTerminalReady(true); + msleep(250); + m_port->setDataTerminalReady(false); } else if (!triedreset) { qDebug() << "No data!!! Attempting reset via reboot command."; communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command"); - port->write("reboot\r\n",8); + m_port->write("reboot\r\n",8); triedreset = true; } else @@ -463,75 +254,43 @@ void SerialLink::run() } } } - /* Serial data isn't arriving that fast normally, this saves the thread - * from consuming too much processing time - */ MG::SLEEP::msleep(SerialLink::poll_interval); - } - if (port) { - port->flushInBuffer(); - port->flushOutBuffer(); - port->close(); - delete port; - port = NULL; - } -} + } // end of forever + + if (m_port) { // [TODO][BB] Not sure we need to close the port here + qDebug() << "Closing Port #"<< __LINE__ << m_port->portName(); + m_port->close(); + delete m_port; + m_port = NULL; - -void SerialLink::checkForBytes() -{ - /* Check if bytes are available */ - if(port && port->isOpen() && port->isWritable()) - { - dataMutex.lock(); - qint64 available = port->bytesAvailable(); - dataMutex.unlock(); - - if(available > 0) - { - readBytes(); - bytesRead += available; - } - else if (available < 0) { - /* Error, close port */ - port->close(); - emit disconnected(); - emit connected(false); - emit communicationError(this->getName(), tr("Could not send data - link %1 is disconnected!").arg(this->getName())); - } + emit disconnected(); + emit connected(false); } -// else -// { -// emit disconnected(); -// emit connected(false); -// } - } void SerialLink::writeBytes(const char* data, qint64 size) { - if(port && port->isOpen()) { - int b = port->write(data, size); + if(m_port && m_port->isOpen()) { +// qDebug() << "writeBytes" << m_portName << "attempting to tx " << size << "bytes."; - if (b > 0) { + QByteArray byteArray(data,size); + { + QMutexLocker writeLocker(&m_writeMutex); + m_transmitBuffer.append(byteArray); + } - // qDebug() << "Serial link " << this->getName() << "transmitted" << b << "bytes:"; +// qDebug() << "writeBytes " << m_portName << "tx'd" << b << "bytes:"; - // Increase write counter - bitsSentTotal += size * 8; + // Increase write counter + m_bitsSentTotal += size * 8; - // int i; - // for (i=0; igetName(), tr("Could not send data - link %1 is disconnected!").arg(this->getName())); - } + // Extra debug logging +// qDebug() << byteArray->toHex(); +// delete byteArray; + } else { + disconnect(); + // Error occured + emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName())); } } @@ -543,18 +302,18 @@ void SerialLink::writeBytes(const char* data, qint64 size) **/ void SerialLink::readBytes() { - dataMutex.lock(); - if(port && port->isOpen()) { + m_dataMutex.lock(); + if(m_port && m_port->isOpen()) { const qint64 maxLength = 2048; char data[maxLength]; - qint64 numBytes = port->bytesAvailable(); + qint64 numBytes = m_port->bytesAvailable(); //qDebug() << "numBytes: " << numBytes; if(numBytes > 0) { /* Read as much data in buffer as possible without overflow */ if(maxLength < numBytes) numBytes = maxLength; - port->read(data, numBytes); + m_port->read(data, numBytes); QByteArray b(data, numBytes); emit bytesReceived(this, b); @@ -566,10 +325,10 @@ void SerialLink::readBytes() // fprintf(stderr,"%02x ", v); // } // fprintf(stderr,"\n"); - bitsReceivedTotal += numBytes * 8; + m_bitsReceivedTotal += numBytes * 8; } } - dataMutex.unlock(); + m_dataMutex.unlock(); } @@ -580,8 +339,8 @@ void SerialLink::readBytes() **/ qint64 SerialLink::bytesAvailable() { - if (port) { - return port->bytesAvailable(); + if (m_port) { + return m_port->bytesAvailable(); } else { return 0; } @@ -594,44 +353,26 @@ qint64 SerialLink::bytesAvailable() **/ bool SerialLink::disconnect() { - if(this->isRunning()) + qDebug() << "disconnect"; + if (m_port) + qDebug() << m_port->portName(); + + if (isRunning()) { + qDebug() << "running so disconnect" << m_port->portName(); { - QMutexLocker locker(&this->m_stoppMutex); - this->m_stopp = true; + QMutexLocker locker(&m_stoppMutex); + m_stopp = true; } - this->wait(); - - // if (port) { - //#if !defined _WIN32 || !defined _WIN64 - /* Block the thread until it returns from run() */ - //#endif - // port->flushInBuffer(); - // port->flushOutBuffer(); - // port->close(); - // delete port; - // port = NULL; - - // if(this->isRunning()) this->terminate(); //stop running the thread, restart it upon connect - - bool closed = true; - //port->isOpen(); + wait(); // This will terminate the thread and close the serial port - emit disconnected(); + emit disconnected(); // [TODO] There are signals from QSerialPort we should use emit connected(false); - if (port) { - port->close(); - } - return closed; - } - else { - // not running - if (port) { - port->close(); - } return true; } + qDebug() << "already disconnected"; + return true; } /** @@ -640,13 +381,15 @@ bool SerialLink::disconnect() * @return True if connection has been established, false if connection couldn't be established. **/ bool SerialLink::connect() -{ - if (this->isRunning()) this->disconnect(); +{ + if (isRunning()) + disconnect(); { QMutexLocker locker(&this->m_stoppMutex); - this->m_stopp = false; + m_stopp = false; } - this->start(LowPriority); + + start(LowPriority); return true; } @@ -660,36 +403,52 @@ bool SerialLink::connect() **/ bool SerialLink::hardwareConnect() { - if(port) { - port->close(); - delete port; + if(m_port) + { + qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port"; + m_port->close(); + delete m_port; + m_port = NULL; } - port = new QSerialPort(porthandle, portSettings); - QObject::connect(port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected())); - port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead); - connectionStartTime = MG::TIME::getGroundTimeNow(); + qDebug() << "SerialLink: hardwareConnect to " << m_portName; + m_port = new QSerialPort(m_portName); - if (!port->open()) + if (m_port == NULL) { - emit communicationUpdate(getName(),"Error opening port: " + port->errorString()); + emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString()); + return false; // couldn't create serial port. } - else + + QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected())); + +// port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead); + m_connectionStartTime = MG::TIME::getGroundTimeNow(); + + if (!m_port->open(QIODevice::ReadWrite)) { - emit communicationUpdate(getName(),"Opened port!"); + emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString()); + m_port->close(); + return false; // couldn't open serial port } - bool connectionUp = isConnected(); - if(connectionUp) { - emit connected(); - emit connected(true); - } + emit communicationUpdate(getName(),"Opened port!"); + + // Need to configure the port + m_port->setBaudRate(m_baud); + m_port->setDataBits(static_cast(m_dataBits)); + m_port->setFlowControl(static_cast(m_flowControl)); + m_port->setStopBits(static_cast(m_stopBits)); + m_port->setParity(static_cast(m_parity)); - //qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << port->portName() << getBaudRate() << getDataBits() << getParityType() << getStopBits(); + emit connected(); + emit connected(true); + qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << m_port->portName() + << getBaudRate() << getDataBits() << getParityType() << getStopBits(); writeSettings(); - return connectionUp; + return true; // successful connection } @@ -700,138 +459,82 @@ bool SerialLink::hardwareConnect() **/ bool SerialLink::isConnected() const { - if (port) { - return port->isOpen(); + + if (m_port) { + bool isConnected = m_port->isOpen(); +// qDebug() << "SerialLink #" << __LINE__ << ":"<< m_port->portName() +// << " isConnected =" << QString::number(isConnected); + return isConnected; } else { +// qDebug() << "SerialLink #" << __LINE__ << ":" << m_portName +// << " isConnected = NULL"; return false; } } int SerialLink::getId() const { - return id; + return m_id; } QString SerialLink::getName() const { - return name; + return m_portName; } -void SerialLink::setName(QString name) -{ - this->name = name; - emit nameChanged(this->name); -} - - /** * This function maps baud rate constants to numerical equivalents. * It relies on the mapping given in qportsettings.h from the QSerialPort library. */ qint64 SerialLink::getNominalDataRate() const { - qint64 dataRate = 0; - switch (portSettings.baudRate()) { - - // Baud rates supported only by POSIX systems -#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) - case QPortSettings::BAUDR_50: - dataRate = 50; - break; - case QPortSettings::BAUDR_75: - dataRate = 75; - break; - case QPortSettings::BAUDR_134: - dataRate = 134; - break; - case QPortSettings::BAUDR_150: - dataRate = 150; - break; - case QPortSettings::BAUDR_200: - dataRate = 200; - break; - case QPortSettings::BAUDR_1800: - dataRate = 1800; - break; -#endif - - // Baud rates supported only by Windows -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - case QPortSettings::BAUDR_14400: - dataRate = 14400; - break; - case QPortSettings::BAUDR_56000: - dataRate = 56000; - break; - case QPortSettings::BAUDR_128000: - dataRate = 128000; - break; - case QPortSettings::BAUDR_256000: - dataRate = 256000; -#endif - - case QPortSettings::BAUDR_110: - dataRate = 110; - break; - case QPortSettings::BAUDR_300: - dataRate = 300; - break; - case QPortSettings::BAUDR_600: - dataRate = 600; - break; - case QPortSettings::BAUDR_1200: - dataRate = 1200; - break; - case QPortSettings::BAUDR_2400: - dataRate = 2400; - break; - case QPortSettings::BAUDR_4800: - dataRate = 4800; - break; - case QPortSettings::BAUDR_9600: - dataRate = 9600; - break; - case QPortSettings::BAUDR_19200: - dataRate = 19200; - break; - case QPortSettings::BAUDR_38400: - dataRate = 38400; - break; - case QPortSettings::BAUDR_57600: - dataRate = 57600; - break; - case QPortSettings::BAUDR_115200: - dataRate = 115200; - break; - case QPortSettings::BAUDR_230400: - dataRate = 230400; - break; - case QPortSettings::BAUDR_460800: - dataRate = 460800; - break; - case QPortSettings::BAUDR_500000: - dataRate = 500000; - break; - case QPortSettings::BAUDR_576000: - dataRate = 576000; - break; - case QPortSettings::BAUDR_921600: - dataRate = 921600; - break; - - // Otherwise do nothing. - case QPortSettings::BAUDR_UNKNOWN: - default: - break; + int baudRate; + if (m_port) { + baudRate = m_port->baudRate(); + } else { + baudRate = m_baud; + } + qint64 dataRate; + switch (baudRate) + { + case QSerialPort::Baud1200: + dataRate = 1200; + break; + case QSerialPort::Baud2400: + dataRate = 2400; + break; + case QSerialPort::Baud4800: + dataRate = 4800; + break; + case QSerialPort::Baud9600: + dataRate = 9600; + break; + case QSerialPort::Baud19200: + dataRate = 19200; + break; + case QSerialPort::Baud38400: + dataRate = 38400; + break; + case QSerialPort::Baud57600: + dataRate = 57600; + break; + case QSerialPort::Baud115200: + dataRate = 115200; + break; + // Otherwise do nothing. + case QSerialPort::UnknownBaud: + default: + dataRate = -1; + break; } return dataRate; } qint64 SerialLink::getTotalUpstream() { - statisticsMutex.lock(); - return bitsSentTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000); - statisticsMutex.unlock(); + m_statisticsMutex.lock(); + return m_bitsSentTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000); + m_statisticsMutex.unlock(); } qint64 SerialLink::getCurrentUpstream() @@ -846,19 +549,19 @@ qint64 SerialLink::getMaxUpstream() qint64 SerialLink::getBitsSent() const { - return bitsSentTotal; + return m_bitsSentTotal; } qint64 SerialLink::getBitsReceived() const { - return bitsReceivedTotal; + return m_bitsReceivedTotal; } qint64 SerialLink::getTotalDownstream() { - statisticsMutex.lock(); - return bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000); - statisticsMutex.unlock(); + m_statisticsMutex.lock(); + return m_bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000); + m_statisticsMutex.unlock(); } qint64 SerialLink::getCurrentDownstream() @@ -885,9 +588,11 @@ int SerialLink::getLinkQuality() const QString SerialLink::getPortName() const { - return porthandle; + return m_portName; } +// We should replace the accessors below with one to get the QSerialPort + int SerialLink::getBaudRate() const { return getNominalDataRate(); @@ -895,43 +600,80 @@ int SerialLink::getBaudRate() const int SerialLink::getBaudRateType() const { - return portSettings.baudRate(); + int baudRate; + if (m_port) { + baudRate = m_port->baudRate(); + } else { + baudRate = m_baud; + } + return baudRate; } int SerialLink::getFlowType() const { - return portSettings.flowControl(); + int flowControl; + if (m_port) { + flowControl = m_port->flowControl(); + } else { + flowControl = m_flowControl; + } + return flowControl; } int SerialLink::getParityType() const { - return portSettings.parity(); + int parity; + if (m_port) { + parity = m_port->parity(); + } else { + parity = m_parity; + } + return parity; } int SerialLink::getDataBitsType() const { - return portSettings.dataBits(); + int dataBits; + if (m_port) { + dataBits = m_port->dataBits(); + } else { + dataBits = m_dataBits; + } + return dataBits; } int SerialLink::getStopBitsType() const { - return portSettings.stopBits(); + int stopBits; + if (m_port) { + stopBits = m_port->stopBits(); + } else { + stopBits = m_stopBits; + } + return stopBits; } int SerialLink::getDataBits() const { - int ret = -1; - switch (portSettings.dataBits()) { - case QPortSettings::DB_5: + int ret; + int dataBits; + if (m_port) { + dataBits = m_port->dataBits(); + } else { + dataBits = m_dataBits; + } + + switch (dataBits) { + case QSerialPort::Data5: ret = 5; break; - case QPortSettings::DB_6: + case QSerialPort::Data6: ret = 6; break; - case QPortSettings::DB_7: + case QSerialPort::Data7: ret = 7; break; - case QPortSettings::DB_8: + case QSerialPort::Data8: ret = 8; break; default: @@ -943,12 +685,18 @@ int SerialLink::getDataBits() const int SerialLink::getStopBits() const { + int stopBits; + if (m_port) { + stopBits = m_port->stopBits(); + } else { + stopBits = m_stopBits; + } int ret = -1; - switch (portSettings.stopBits()) { - case QPortSettings::STOP_1: + switch (stopBits) { + case QSerialPort::OneStop: ret = 1; break; - case QPortSettings::STOP_2: + case QSerialPort::TwoStop: ret = 2; break; default: @@ -960,56 +708,40 @@ int SerialLink::getStopBits() const bool SerialLink::setPortName(QString portName) { - if(portName.trimmed().length() > 0) { - bool reconnect = false; - if (isConnected()) reconnect = true; - disconnect(); - - this->porthandle = portName.trimmed(); - setName(tr("serial port ") + portName.trimmed()); -#ifdef _WIN32 - // Port names above 20 need the network path format - if the port name is not already in this format - // catch this special case - if (!this->porthandle.startsWith("\\")) { - // Append \\.\ before the port handle. Additional backslashes are used for escaping. - this->porthandle = "\\\\.\\" + this->porthandle; - } -#endif + qDebug() << "current portName " << m_portName; + qDebug() << "setPortName to " << portName; + bool accepted = false; + if ((portName != m_portName) + && (portName.trimmed().length() > 0)) { + m_portName = portName.trimmed(); +// m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this? + if(m_port) + m_port->setPortName(portName); - if(reconnect) connect(); - return true; - } else { - return false; + emit nameChanged(m_portName); // [TODO] maybe we can eliminate this + emit updateLink(this); + return accepted; } + return false; } bool SerialLink::setBaudRateType(int rateIndex) { - bool reconnect = false; - bool accepted = true; // This is changed if none of the data rates matches - if(isConnected()) reconnect = true; - disconnect(); + Q_ASSERT_X(m_port != NULL, "setBaudRateType", "m_port is NULL"); + // These minimum and maximum baud rates were based on those enumerated in qserialport.h + bool result; + const int minBaud = (int)QSerialPort::Baud1200; + const int maxBaud = (int)QSerialPort::Baud115200; - // These minimum and maximum baud rates were based on those enumerated in qportsettings.h. -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - const int minBaud = (int)QPortSettings::BAUDR_110; - const int maxBaud = (int)QPortSettings::BAUDR_921600; -#elif defined(Q_OS_LINUX) - const int minBaud = (int)QPortSettings::BAUDR_50; - const int maxBaud = (int)QPortSettings::BAUDR_921600; -#elif defined(Q_OS_UNIX) || defined(Q_OS_DARWIN) - const int minBaud = (int)QPortSettings::BAUDR_50; - const int maxBaud = (int)QPortSettings::BAUDR_921600; -#endif - - if (rateIndex >= minBaud && rateIndex <= maxBaud) + if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud)) { - portSettings.setBaudRate((QPortSettings::BaudRate)rateIndex); + result = m_port->setBaudRate(static_cast(rateIndex)); + emit updateLink(this); + return result; } - if(reconnect) connect(); - return accepted; + return false; } bool SerialLink::setBaudRateString(const QString& rate) @@ -1022,260 +754,111 @@ bool SerialLink::setBaudRateString(const QString& rate) bool SerialLink::setBaudRate(int rate) { - bool reconnect = false; - bool accepted = true; // This is changed if none of the data rates matches - if(isConnected()) { - reconnect = true; - } - disconnect(); - - // This switch-statment relies on the mapping given in qportsettings.h from the QSerialPort library. - switch (rate) { - - // Baud rates supported only by non-Windows systems -#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) - case 50: - portSettings.setBaudRate(QPortSettings::BAUDR_50); - break; - case 75: - portSettings.setBaudRate(QPortSettings::BAUDR_75); - break; - case 134: - portSettings.setBaudRate(QPortSettings::BAUDR_134); - break; - case 150: - portSettings.setBaudRate(QPortSettings::BAUDR_150); - break; - case 200: - portSettings.setBaudRate(QPortSettings::BAUDR_200); - break; - case 1800: - portSettings.setBaudRate(QPortSettings::BAUDR_1800); - break; -#endif - - // Baud rates supported only by windows -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - case 14400: - portSettings.setBaudRate(QPortSettings::BAUDR_14400); - break; - case 56000: - portSettings.setBaudRate(QPortSettings::BAUDR_56000); - break; - case 128000: - portSettings.setBaudRate(QPortSettings::BAUDR_128000); - break; - case 256000: - portSettings.setBaudRate(QPortSettings::BAUDR_256000); - break; -#endif - - // Supported by all OSes: - case 110: - portSettings.setBaudRate(QPortSettings::BAUDR_110); - break; - case 300: - portSettings.setBaudRate(QPortSettings::BAUDR_300); - break; - case 600: - portSettings.setBaudRate(QPortSettings::BAUDR_600); - break; - case 1200: - portSettings.setBaudRate(QPortSettings::BAUDR_1200); - break; - case 2400: - portSettings.setBaudRate(QPortSettings::BAUDR_2400); - break; - case 4800: - portSettings.setBaudRate(QPortSettings::BAUDR_4800); - break; - case 9600: - portSettings.setBaudRate(QPortSettings::BAUDR_9600); - break; - case 19200: - portSettings.setBaudRate(QPortSettings::BAUDR_19200); - break; - case 38400: - portSettings.setBaudRate(QPortSettings::BAUDR_38400); - break; - case 57600: - portSettings.setBaudRate(QPortSettings::BAUDR_57600); - break; - case 115200: - portSettings.setBaudRate(QPortSettings::BAUDR_115200); - break; - case 230400: - portSettings.setBaudRate(QPortSettings::BAUDR_230400); - break; - case 460800: - portSettings.setBaudRate(QPortSettings::BAUDR_460800); - break; - case 500000: - portSettings.setBaudRate(QPortSettings::BAUDR_500000); - break; - case 576000: - portSettings.setBaudRate(QPortSettings::BAUDR_576000); - break; - case 921600: - portSettings.setBaudRate(QPortSettings::BAUDR_921600); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (rate != m_baud) { + m_baud = rate; + accepted = true; + if (m_port) + accepted = m_port->setBaudRate(rate); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; - } bool SerialLink::setFlowType(int flow) { - bool reconnect = false; - bool accepted = true; - if(isConnected()) reconnect = true; - disconnect(); - - switch (flow) { - case (int)QPortSettings::FLOW_OFF: - portSettings.setFlowControl(QPortSettings::FLOW_OFF); - break; - case (int)QPortSettings::FLOW_HARDWARE: - portSettings.setFlowControl(QPortSettings::FLOW_HARDWARE); - break; - case (int)QPortSettings::FLOW_XONXOFF: - portSettings.setFlowControl(QPortSettings::FLOW_XONXOFF); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (flow != m_flowControl) { + m_flowControl = static_cast(flow); + accepted = true; + if (m_port) + accepted = m_port->setFlowControl(static_cast(flow)); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; } bool SerialLink::setParityType(int parity) { - bool reconnect = false; - bool accepted = true; - if (isConnected()) reconnect = true; - disconnect(); - - switch (parity) { - case (int)QPortSettings::PAR_NONE: - portSettings.setParity(QPortSettings::PAR_NONE); - break; - case (int)QPortSettings::PAR_ODD: - portSettings.setParity(QPortSettings::PAR_ODD); - break; - case (int)QPortSettings::PAR_EVEN: - portSettings.setParity(QPortSettings::PAR_EVEN); - break; - case (int)QPortSettings::PAR_SPACE: - portSettings.setParity(QPortSettings::PAR_SPACE); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (parity != m_parity) { + m_parity = static_cast(parity); + accepted = true; + if (m_port) { + switch (parity) { + case QSerialPort::NoParity: + accepted = m_port->setParity(QSerialPort::NoParity); + break; + case 1: // Odd Parity setting for backwards compatibilty + accepted = m_port->setParity(QSerialPort::OddParity); + break; + case QSerialPort::EvenParity: + accepted = m_port->setParity(QSerialPort::EvenParity); + break; + case QSerialPort::OddParity: + accepted = m_port->setParity(QSerialPort::OddParity); + break; + default: + // If none of the above cases matches, there must be an error + accepted = false; + break; + } + emit updateLink(this); + } } - - if (reconnect) connect(); return accepted; } bool SerialLink::setDataBits(int dataBits) { - //qDebug() << "Setting" << dataBits << "data bits"; - bool reconnect = false; - if (isConnected()) reconnect = true; - bool accepted = true; - disconnect(); - - switch (dataBits) { - case 5: - portSettings.setDataBits(QPortSettings::DB_5); - break; - case 6: - portSettings.setDataBits(QPortSettings::DB_6); - break; - case 7: - portSettings.setDataBits(QPortSettings::DB_7); - break; - case 8: - portSettings.setDataBits(QPortSettings::DB_8); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (dataBits != m_dataBits) { + m_dataBits = static_cast(dataBits); + accepted = true; + if (m_port) + accepted = m_port->setDataBits(static_cast(dataBits)); + emit updateLink(this); } - - if(reconnect) connect(); - return accepted; } bool SerialLink::setStopBits(int stopBits) { - bool reconnect = false; - bool accepted = true; - if(isConnected()) reconnect = true; - disconnect(); - - switch (stopBits) { - case 1: - portSettings.setStopBits(QPortSettings::STOP_1); - break; - case 2: - portSettings.setStopBits(QPortSettings::STOP_2); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + // Note 3 is OneAndAHalf stopbits. + bool accepted = false; + if (stopBits != m_stopBits) { + m_stopBits = static_cast(stopBits); + accepted = true; + if (m_port) + accepted = m_port->setStopBits(static_cast(stopBits)); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; } bool SerialLink::setDataBitsType(int dataBits) { - bool reconnect = false; bool accepted = false; - - if (isConnected()) reconnect = true; - disconnect(); - - if (dataBits >= (int)QPortSettings::DB_5 && dataBits <= (int)QPortSettings::DB_8) { - portSettings.setDataBits((QPortSettings::DataBits) dataBits); - - if(reconnect) connect(); + if (dataBits != m_dataBits) { + m_dataBits = static_cast(dataBits); accepted = true; + if (m_port) + accepted = m_port->setDataBits(static_cast(dataBits)); + emit updateLink(this); } - return accepted; } bool SerialLink::setStopBitsType(int stopBits) { - bool reconnect = false; bool accepted = false; - if(isConnected()) reconnect = true; - disconnect(); - - if (stopBits >= (int)QPortSettings::STOP_1 && stopBits <= (int)QPortSettings::STOP_2) { - portSettings.setStopBits((QPortSettings::StopBits) stopBits); - - if(reconnect) connect(); + if (stopBits != m_stopBits) { + m_stopBits = static_cast(stopBits); accepted = true; + if (m_port) + accepted = m_port->setStopBits(static_cast(stopBits)); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; } diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h index 6e71b3a7ac76b1e5042ec82d18740e73fefcef7f..25262f00b3e976ec9b8df98de7592f2213c599d1 100644 --- a/src/comm/SerialLink.h +++ b/src/comm/SerialLink.h @@ -36,13 +36,9 @@ This file is part of the QGROUNDCONTROL project #include #include #include -#include "qserialport.h" +#include #include #include "SerialLinkInterface.h" -#ifdef _WIN32 -#include "windows.h" -#endif - /** * @brief The SerialLink class provides cross-platform access to serial links. @@ -69,7 +65,9 @@ public: static const int poll_interval = SERIAL_POLL_INTERVAL; ///< Polling interval, defined in configuration.h /** @brief Get a list of the currently available ports */ - QVector* getCurrentPorts(); + QList getCurrentPorts(); + + void requestReset(); bool isConnected() const; qint64 bytesAvailable(); @@ -108,11 +106,15 @@ public: void writeSettings(); void run(); + void run2(); int getLinkQuality() const; bool isFullDuplex() const; int getId() const; +signals: //[TODO] Refactor to Linkinterface + void updateLink(LinkInterface*); + public slots: bool setPortName(QString portName); bool setBaudRate(int rate); @@ -140,40 +142,39 @@ public slots: bool connect(); bool disconnect(); -protected slots: - void checkForBytes(); - protected: - quint64 bytesRead; - TNX::QSerialPort * port; - TNX::QPortSettings portSettings; -#ifdef _WIN32 - HANDLE winPort; - DCB winPortSettings; -#endif - QString porthandle; - QString name; - int timeout; - int id; - - quint64 bitsSentTotal; - quint64 bitsSentShortTerm; - quint64 bitsSentCurrent; - quint64 bitsSentMax; - quint64 bitsReceivedTotal; - quint64 bitsReceivedShortTerm; - quint64 bitsReceivedCurrent; - quint64 bitsReceivedMax; - quint64 connectionStartTime; - QMutex statisticsMutex; - QMutex dataMutex; - QVector* ports; + quint64 m_bytesRead; + QSerialPort* m_port; + int m_baud; + int m_dataBits; + int m_flowControl; + int m_stopBits; + int m_parity; + QString m_portName; +// QString m_name; + int m_timeout; + int m_id; + + quint64 m_bitsSentTotal; + quint64 m_bitsSentShortTerm; + quint64 m_bitsSentCurrent; + quint64 m_bitsSentMax; + quint64 m_bitsReceivedTotal; + quint64 m_bitsReceivedShortTerm; + quint64 m_bitsReceivedCurrent; + quint64 m_bitsReceivedMax; + quint64 m_connectionStartTime; + QMutex m_statisticsMutex; + QMutex m_dataMutex; + QList m_ports; private: - volatile bool m_stopp; + volatile bool m_stopp; + volatile bool m_reqReset; QMutex m_stoppMutex; + QMutex m_writeMutex; + QByteArray m_transmitBuffer; - void setName(QString name); bool hardwareConnect(); signals: diff --git a/src/comm/SerialLinkInterface.h b/src/comm/SerialLinkInterface.h index 5421027b1a126d49cc664fe406361d3c2261b5d1..3d80f3584a070490b40057c4bd4bed0098da553d 100644 --- a/src/comm/SerialLinkInterface.h +++ b/src/comm/SerialLinkInterface.h @@ -42,12 +42,12 @@ class SerialLinkInterface : public LinkInterface Q_OBJECT public: - virtual QVector* getCurrentPorts() = 0; + virtual QList getCurrentPorts() = 0; virtual QString getPortName() const = 0; virtual int getBaudRate() const = 0; virtual int getDataBits() const = 0; virtual int getStopBits() const = 0; - + virtual void requestReset() = 0; virtual int getBaudRateType() const = 0; virtual int getFlowType() const = 0; virtual int getParityType() const = 0; diff --git a/src/comm/UDPLink.h b/src/comm/UDPLink.h index d51f08c6f6f79759a9d198be84e381d7fa684ea8..4973eaf230dc41624107c65600712302bdda426f 100644 --- a/src/comm/UDPLink.h +++ b/src/comm/UDPLink.h @@ -49,6 +49,8 @@ public: //UDPLink(QHostAddress host = "239.255.76.67", quint16 port = 7667); ~UDPLink(); + void requestReset() { } + bool isConnected() const; qint64 bytesAvailable(); int getPort() const { diff --git a/src/comm/XbeeLink.h b/src/comm/XbeeLink.h index 00dfa857384aede6268ba662a8e187320569d182..52ff65706ef28a260a5b01823fa64957a2f42435 100644 --- a/src/comm/XbeeLink.h +++ b/src/comm/XbeeLink.h @@ -20,8 +20,9 @@ public: ~XbeeLink(); public: // virtual functions from XbeeLinkInterface - QString getPortName() const; - int getBaudRate() const; + QString getPortName(); + void requestReset() { } + int getBaudRate(); public slots: // virtual functions from XbeeLinkInterface bool setPortName(QString portName); @@ -71,4 +72,4 @@ private: }; -#endif // _XBEELINK_H_ \ No newline at end of file +#endif // _XBEELINK_H_ diff --git a/src/configuration.h b/src/configuration.h index 88e19d8258c054e84e240da0995cd1a7484b6a58..72f8556e7e283b269ba5e44f01e55389b275f80a 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -11,7 +11,7 @@ #define WITH_TEXT_TO_SPEECH 1 #define QGC_APPLICATION_NAME "QGroundControl" -#define QGC_APPLICATION_VERSION "v. 1.0.9 (beta RC1)" +#define QGC_APPLICATION_VERSION "v1.1 (beta)" namespace QGC diff --git a/src/uas/UASManager.cc b/src/uas/UASManager.cc index c03cec06edb21bffd54897d5718e056cb68fc350..072c7aea7a7a317b6ec19854a88b47615d20d80d 100644 --- a/src/uas/UASManager.cc +++ b/src/uas/UASManager.cc @@ -244,11 +244,11 @@ void UASManager::uavChangedHomePosition(int uav, double lat, double lon, double **/ UASManager::UASManager() : activeUAS(NULL), + offlineUASWaypointManager(NULL), homeLat(47.3769), homeLon(8.549444), homeAlt(470.0), - homeFrame(MAV_FRAME_GLOBAL), - offlineUASWaypointManager(NULL) + homeFrame(MAV_FRAME_GLOBAL) { loadSettings(); setLocalNEDSafetyBorders(1, -1, 0, -1, 1, -1); diff --git a/src/ui/CommConfigurationWindow.cc b/src/ui/CommConfigurationWindow.cc index b1fbac86e5ebe36232ded67f319358698c4573c9..cf63e79123f9d306c9161f6e55d50ef978402cdc 100644 --- a/src/ui/CommConfigurationWindow.cc +++ b/src/ui/CommConfigurationWindow.cc @@ -55,7 +55,7 @@ This file is part of the QGROUNDCONTROL project #include "LinkManager.h" #include "MainWindow.h" -CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolInterface* protocol, QWidget *parent) : QWidget(NULL) +CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolInterface* protocol, QWidget *parent) : QWidget(parent) { this->link = link; diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index e695f0bbb9590ad42e0b2a3a4d74f7d3a55ea523..2b78425fec0b440330de2c7b3fc679d510c28b5e 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -38,6 +38,7 @@ This file is part of the QGROUNDCONTROL project #include #include #include +#include #include "dockwidgettitlebareventfilter.h" #include "QGC.h" #include "MAVLinkSimulationLink.h" @@ -65,6 +66,9 @@ This file is part of the QGROUNDCONTROL project #include "QGCTabbedInfoView.h" #include "UASRawStatusView.h" #include "PrimaryFlightDisplay.h" +#include +#include +#include #ifdef QGC_OSG_ENABLED #include "Q3DWidgetFactory.h" @@ -113,6 +117,11 @@ MainWindow::MainWindow(QWidget *parent): darkStyleFileName(defaultDarkStyle), lightStyleFileName(defaultLightStyle), autoReconnect(false), + #ifdef APM_TOOLBAR_DEFAULT + apmToolBarEnabled(true), + #else + apmToolBarEnabled(false), + #endif lowPowerMode(false), isAdvancedMode(false), dockWidgetTitleBarEnabled(true) @@ -184,28 +193,33 @@ void MainWindow::init() centerStack = new QStackedWidget(this); setCentralWidget(centerStack); + // Load Toolbar - toolBar = new QGCToolBar(this); - this->addToolBar(toolBar); - - // Add actions for average users (displayed next to each other) - QList actions; - actions << ui.actionFlightView; - actions << ui.actionMissionView; - actions << ui.actionConfiguration_2; - toolBar->setPerspectiveChangeActions(actions); - - // Add actions for advanced users (displayed in dropdown under "advanced") - QList advancedActions; - advancedActions << ui.actionSimulation_View; - advancedActions << ui.actionEngineersView; - - toolBar->setPerspectiveChangeAdvancedActions(advancedActions); + if (!apmToolBarEnabled) { + toolBar = new QGCToolBar(this); + this->addToolBar(toolBar); + + // Add actions for average users (displayed next to each other) + QList actions; + actions << ui.actionFlightView; + actions << ui.actionMissionView; + //actions << ui.actionConfiguration_2; + actions << ui.actionHardwareConfig; + toolBar->setPerspectiveChangeActions(actions); + + // Add actions for advanced users (displayed in dropdown under "advanced") + QList advancedActions; + advancedActions << ui.actionSimulation_View; + advancedActions << ui.actionEngineersView; + + toolBar->setPerspectiveChangeAdvancedActions(advancedActions); + } + customStatusBar = new QGCStatusBar(this); setStatusBar(customStatusBar); statusBar()->setSizeGripEnabled(true); - emit initStatusChanged(tr("Building common widgets"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); + emit initStatusChanged(tr("Building common widgets."), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); buildCommonWidgets(); connectCommonWidgets(); @@ -225,6 +239,28 @@ void MainWindow::init() connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*))); + if (apmToolBarEnabled) { + // Add the APM 'toolbar' + + APMToolBar *apmToolBar = new APMToolBar(this); + apmToolBar->setFlightViewAction(ui.actionFlightView); + apmToolBar->setFlightPlanViewAction(ui.actionMissionView); + apmToolBar->setHardwareViewAction(ui.actionHardwareConfig); + apmToolBar->setSoftwareViewAction(ui.actionSoftwareConfig); + apmToolBar->setSimulationViewAction(ui.actionSimulation_View); + apmToolBar->setTerminalViewAction(ui.actionSimulation_View); + + QDockWidget *widget = new QDockWidget(tr("APM Tool Bar"),this); + widget->setWidget(apmToolBar); + widget->setMinimumHeight(72); + widget->setMaximumHeight(72); + widget->setMinimumWidth(1024); + widget->setFeatures(QDockWidget::NoDockWidgetFeatures); + widget->setTitleBarWidget(new QWidget(this)); // Disables the title bar + // /*widget*/->setStyleSheet("QDockWidget { border: 0px solid #FFFFFF; border-radius: 0px; border-bottom: 0px;}"); + this->addDockWidget(Qt::TopDockWidgetArea, widget); + } + // Connect user interface devices emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); joystickWidget = 0; @@ -356,15 +392,6 @@ MainWindow::~MainWindow() void MainWindow::resizeEvent(QResizeEvent * event) { - if (width() > 1200) - { - toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - } - else - { - toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); - } - QMainWindow::resizeEvent(event); } @@ -488,12 +515,20 @@ void MainWindow::buildCommonWidgets() if (!configView) { configView = new SubMainWindow(this); - configView->setObjectName("VIEW_CONFIGURATION"); - configView->setCentralWidget(new QGCVehicleConfig(this)); - addCentralWidget(configView,"Config"); - centralWidgetToDockWidgetsMap[VIEW_CONFIGURATION] = QMap(); + configView->setObjectName("VIEW_HARDWARE_CONFIG"); + configView->setCentralWidget(new ApmHardwareConfig(this)); + addCentralWidget(configView,"Hardware"); + centralWidgetToDockWidgetsMap[VIEW_HARDWARE_CONFIG] = QMap(); } + if (!softwareConfigView) + { + softwareConfigView = new SubMainWindow(this); + softwareConfigView->setObjectName("VIEW_SOFTWARE_CONFIG"); + softwareConfigView->setCentralWidget(new ApmSoftwareConfig(this)); + addCentralWidget(softwareConfigView,"Software"); + centralWidgetToDockWidgetsMap[VIEW_SOFTWARE_CONFIG] = QMap(); + } if (!engineeringView) { engineeringView = new SubMainWindow(this); @@ -583,8 +618,10 @@ void MainWindow::buildCommonWidgets() } createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5); - createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5); + createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5); + + createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5); createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8); QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this); @@ -894,6 +931,7 @@ void MainWindow::showTool(bool show) void MainWindow::addCentralWidget(QWidget* widget, const QString& title) { Q_UNUSED(title); + // Check if this widget already has been added if (centerStack->indexOf(widget) == -1) { @@ -931,7 +969,7 @@ void MainWindow::showHILConfigurationWidget(UASInterface* uas) //createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea); QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this); - QString hilDockName = tr("HIL Config %1").arg(uas->getUASName()); + QString hilDockName = tr("HIL Config %1").arg(uas->getUASName()); QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockName.toUpper().replace(" ", "_"),VIEW_SIMULATION,Qt::LeftDockWidgetArea); hilDocks.insert(mav->getUASID(), hilDock); @@ -1146,6 +1184,7 @@ void MainWindow::loadSettings() lightStyleFileName = settings.value("LIGHT_STYLE_FILENAME", lightStyleFileName).toString(); lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool(); dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled).toBool(); + apmToolBarEnabled = settings.value("APM_SPECIFIC_TOOLBAR", apmToolBarEnabled).toBool(); settings.endGroup(); enableDockWidgetTitleBars(dockWidgetTitleBarEnabled); } @@ -1158,6 +1197,7 @@ void MainWindow::storeSettings() settings.setValue("CURRENT_STYLE", currentStyle); settings.setValue("DARK_STYLE_FILENAME", darkStyleFileName); settings.setValue("LIGHT_STYLE_FILENAME", lightStyleFileName); + settings.setValue("APM_SPECIFIC_TOOLBAR", apmToolBarEnabled); settings.endGroup(); if (!aboutToCloseFlag && isVisible()) { @@ -1352,7 +1392,9 @@ void MainWindow::connectCommonActions() perspectives->addAction(ui.actionFlightView); perspectives->addAction(ui.actionSimulation_View); perspectives->addAction(ui.actionMissionView); - perspectives->addAction(ui.actionConfiguration_2); + //perspectives->addAction(ui.actionConfiguration_2); + perspectives->addAction(ui.actionHardwareConfig); + perspectives->addAction(ui.actionSoftwareConfig); perspectives->addAction(ui.actionFirmwareUpdateView); perspectives->addAction(ui.actionUnconnectedView); perspectives->setExclusive(true); @@ -1383,10 +1425,15 @@ void MainWindow::connectCommonActions() ui.actionMissionView->setChecked(true); ui.actionMissionView->activate(QAction::Trigger); } - if (currentView == VIEW_CONFIGURATION) + if (currentView == VIEW_HARDWARE_CONFIG) + { + ui.actionHardwareConfig->setChecked(true); + ui.actionHardwareConfig->activate(QAction::Trigger); + } + if (currentView == VIEW_SOFTWARE_CONFIG) { - ui.actionConfiguration_2->setChecked(true); - ui.actionConfiguration_2->activate(QAction::Trigger); + ui.actionSoftwareConfig->setChecked(true); + ui.actionSoftwareConfig->activate(QAction::Trigger); } if (currentView == VIEW_FIRMWAREUPDATE) { @@ -1429,7 +1476,8 @@ void MainWindow::connectCommonActions() connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView())); connect(ui.actionMissionView, SIGNAL(triggered()), this, SLOT(loadOperatorView())); connect(ui.actionUnconnectedView, SIGNAL(triggered()), this, SLOT(loadUnconnectedView())); - connect(ui.actionConfiguration_2,SIGNAL(triggered()),this,SLOT(loadConfigurationView())); + connect(ui.actionHardwareConfig,SIGNAL(triggered()),this,SLOT(loadHardwareConfigView())); + connect(ui.actionSoftwareConfig,SIGNAL(triggered()),this,SLOT(loadSoftwareConfigView())); connect(ui.actionFirmwareUpdateView, SIGNAL(triggered()), this, SLOT(loadFirmwareUpdateView())); connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView())); @@ -1547,6 +1595,29 @@ void MainWindow::addLink() } } + +bool MainWindow::configLink(LinkInterface *link) +{ + // Go searching for this link's configuration window + QList actions = ui.menuNetwork->actions(); + + bool found(false); + + const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link)); + const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId()); + + foreach (QAction* action, actions) + { + if (action->data().toInt() == linkID) + { // LinkManager::instance()->getLinks().indexOf(link) + found = true; + action->trigger(); // Show the Link Config Dialog + } + } + + return found; +} + void MainWindow::addLink(LinkInterface *link) { // IMPORTANT! KEEP THESE TWO LINES @@ -1576,7 +1647,7 @@ void MainWindow::addLink(LinkInterface *link) if (!found) { // || udp - CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this); + CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, NULL); commsWidgetList.append(commWidget); connect(commWidget,SIGNAL(destroyed(QObject*)),this,SLOT(commsWidgetDestroyed(QObject*))); QAction* action = commWidget->getAction(); @@ -1592,6 +1663,11 @@ void MainWindow::addLink(LinkInterface *link) } } } + +//void MainWindow::configLink(LinkInterface *link) +//{ + +//} void MainWindow::commsWidgetDestroyed(QObject *obj) { if (commsWidgetList.contains(obj)) @@ -1893,9 +1969,12 @@ void MainWindow::loadViewState() // Load defaults switch (currentView) { - case VIEW_CONFIGURATION: + case VIEW_HARDWARE_CONFIG: centerStack->setCurrentWidget(configView); break; + case VIEW_SOFTWARE_CONFIG: + centerStack->setCurrentWidget(softwareConfigView); + break; case VIEW_ENGINEER: centerStack->setCurrentWidget(engineeringView); break; @@ -1986,13 +2065,24 @@ void MainWindow::loadOperatorView() loadViewState(); } } -void MainWindow::loadConfigurationView() +void MainWindow::loadHardwareConfigView() +{ + if (currentView != VIEW_HARDWARE_CONFIG) + { + storeViewState(); + currentView = VIEW_HARDWARE_CONFIG; + ui.actionHardwareConfig->setChecked(true); + loadViewState(); + } +} + +void MainWindow::loadSoftwareConfigView() { - if (currentView != VIEW_CONFIGURATION) + if (currentView != VIEW_SOFTWARE_CONFIG) { storeViewState(); - currentView = VIEW_CONFIGURATION; - ui.actionConfiguration_2->setChecked(true); + currentView = VIEW_SOFTWARE_CONFIG; + ui.actionSoftwareConfig->setChecked(true); loadViewState(); } } diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index b757d67539a78b1e718fe18b63f045e596a5eb9e..5b8f652b63c5fb52213d45233281be762a3a165b 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -30,7 +30,6 @@ This file is part of the QGROUNDCONTROL project #ifndef _MAINWINDOW_H_ #define _MAINWINDOW_H_ - #include #include #include @@ -155,6 +154,12 @@ public: return autoReconnect; } + /** @brief Get custom toolbar setting */ + bool isApmToolBarEnabled() + { + return apmToolBarEnabled; + } + /** @brief Get title bar mode setting */ bool dockWidgetTitleBarsEnabled() { @@ -184,6 +189,7 @@ public slots: /** @brief Add a communication link */ void addLink(); void addLink(LinkInterface* link); + bool configLink(LinkInterface *link); void configure(); /** @brief Set the currently controlled UAS */ void setActiveUAS(UASInterface* uas); @@ -200,8 +206,9 @@ public slots: /** @brief Sets advanced mode, allowing for editing of tool widget locations */ void setAdvancedMode(); - /** @brief Load configuration view */ - void loadConfigurationView(); + /** @brief Load configuration views */ + void loadHardwareConfigView(); + void loadSoftwareConfigView(); /** @brief Load default view when no MAV is connected */ void loadUnconnectedView(); /** @brief Load view for pilot */ @@ -228,6 +235,11 @@ public slots: void enableDockWidgetTitleBars(bool enabled); /** @brief Automatically reconnect last link */ void enableAutoReconnect(bool enabled); + /** @brief Enable APM specific toolbar */ + void enableApmToolbar(bool enabled) { + apmToolBarEnabled = enabled; + } + /** @brief Save power by reducing update rates */ void enableLowPowerMode(bool enabled) { lowPowerMode = enabled; } /** @brief Load a specific style. @@ -309,7 +321,8 @@ protected: VIEW_SIMULATION, VIEW_MAVLINK, VIEW_FIRMWAREUPDATE, - VIEW_CONFIGURATION, + VIEW_HARDWARE_CONFIG, + VIEW_SOFTWARE_CONFIG, VIEW_UNCONNECTED, ///< View in unconnected mode, when no UAS is available VIEW_FULL ///< All widgets shown at once } VIEW_SECTIONS; @@ -376,6 +389,7 @@ protected: QPointer plannerView; QPointer pilotView; QPointer configView; + QPointer softwareConfigView; QPointer mavlinkView; QPointer engineeringView; QPointer simView; @@ -467,6 +481,7 @@ protected: QString darkStyleFileName; QString lightStyleFileName; bool autoReconnect; + bool apmToolBarEnabled; Qt::WindowStates windowStateVal; bool lowPowerMode; ///< If enabled, QGC reduces the update rates of all widgets QGCFlightGearLink* fgLink; diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui index 41fb9846a90aa862c4c32983e9beb1619ac81ab3..339ded2613984c265e9ce662793a553f35348174 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -6,14 +6,14 @@ 0 0 - 800 - 500 + 1024 + 600 - 800 - 500 + 1024 + 600 @@ -50,8 +50,8 @@ 0 0 - 800 - 25 + 1024 + 22 @@ -97,7 +97,8 @@ - + + @@ -275,7 +276,7 @@ - :/files/images/status/weather-overcast.svg:/files/images/status/weather-overcast.svg + :/files/images/categories/applications-internet.svg:/files/images/categories/applications-internet.svg Mission @@ -441,7 +442,7 @@ Open the simulation view - + true @@ -450,7 +451,7 @@ :/files/images/categories/preferences-system.svg:/files/images/categories/preferences-system.svg - Config + Hardware Configuration options of the vehicle. @@ -469,6 +470,15 @@ Simulation + + + + :/files/images/categories/applications-system.svg:/files/images/categories/applications-system.svg + + + Software + + diff --git a/src/ui/QGCParamWidget.cc b/src/ui/QGCParamWidget.cc index 4e9700a20cc7650d811cabf8ce8fe4f89bcbf36c..4758fca14ea979790fa4de97899ac76924ee6c5b 100644 --- a/src/ui/QGCParamWidget.cc +++ b/src/ui/QGCParamWidget.cc @@ -1019,6 +1019,11 @@ void QGCParamWidget::setParameter(int component, QString parameterName, QVariant statusLabel->setText(tr("REJ. %1 > max").arg(value.toDouble())); return; } + if (parameters.value(component)->value(parameterName) == value) + { + statusLabel->setText(tr("REJ. %1 > max").arg(value.toDouble())); + return; + } switch (parameters.value(component)->value(parameterName).type()) { diff --git a/src/ui/QGCSettingsWidget.cc b/src/ui/QGCSettingsWidget.cc index 5f16ce1170e0cea32dca5a85e275164254d6a421..c7468dff292500971eb5b4bdb4bffbe88581fa0f 100644 --- a/src/ui/QGCSettingsWidget.cc +++ b/src/ui/QGCSettingsWidget.cc @@ -52,6 +52,10 @@ QGCSettingsWidget::QGCSettingsWidget(QWidget *parent, Qt::WindowFlags flags) : ui->titleBarCheckBox->setChecked(mainWindow->dockWidgetTitleBarsEnabled()); connect(ui->titleBarCheckBox,SIGNAL(clicked(bool)),mainWindow,SLOT(enableDockWidgetTitleBars(bool))); + // APM toolbar + ui->apmToolBarCheckBox->setChecked(mainWindow->isApmToolBarEnabled()); + connect(ui->apmToolBarCheckBox, SIGNAL(clicked(bool)), mainWindow, SLOT(enableApmToolbar(bool))); + // Intialize the style UI to the proper values obtained from the MainWindow. MainWindow::QGC_MAINWINDOW_STYLE style = mainWindow->getStyle(); ui->styleChooser->setCurrentIndex(style); diff --git a/src/ui/QGCSettingsWidget.ui b/src/ui/QGCSettingsWidget.ui index 746b37fb3ef44f86ae9935143c466b8c68fef4b5..2097b866e9fdca519849a4b163d3f4fd3aedef99 100644 --- a/src/ui/QGCSettingsWidget.ui +++ b/src/ui/QGCSettingsWidget.ui @@ -7,7 +7,7 @@ 0 0 528 - 321 + 347 @@ -72,6 +72,13 @@ + + + + Show ArduPilot specific toolbar (restart QGC after change) + + + diff --git a/src/ui/QGCStatusBar.cc b/src/ui/QGCStatusBar.cc index 9d542615e7ae419dca58bf7029cd4f14ec574669..9e2fbacf1586079259a00721c01838cad52077dc 100644 --- a/src/ui/QGCStatusBar.cc +++ b/src/ui/QGCStatusBar.cc @@ -47,16 +47,11 @@ QGCStatusBar::QGCStatusBar(QWidget *parent) : void QGCStatusBar::paintEvent(QPaintEvent * event) { + Q_UNUSED(event); QPainter p(this); QStyleOption opt; opt.initFrom(this); style()->drawPrimitive(QStyle::PE_PanelStatusBar, &opt, &p, this); - //QStatusBar::paintEvent(event); -// if (currentMessage().length() == 0) { -// QStatusBar::paintEvent(event); -// } else { - -// } } void QGCStatusBar::setLogPlayer(QGCMAVLinkLogPlayer* player) @@ -64,12 +59,6 @@ void QGCStatusBar::setLogPlayer(QGCMAVLinkLogPlayer* player) this->player = player; addPermanentWidget(player); connect(toggleLoggingButton, SIGNAL(clicked(bool)), this, SLOT(logging(bool))); - //connect(MainWindow::instance()->getMAVLink(), SIGNAL(loggingChanged(bool)), toggleLoggingButton, SLOT(setChecked(bool))); - - // XXX Mutex issue if called like this -// toggleLoggingButton->blockSignals(true); -// toggleLoggingButton->setChecked(MainWindow::instance()->getMAVLink()->loggingEnabled()); -// toggleLoggingButton->blockSignals(false); } void QGCStatusBar::logging(bool checked) diff --git a/src/ui/QGCToolBar.cc b/src/ui/QGCToolBar.cc index 294fb60f9ec1e7c5a3ae8c2d98c787709849d871..54531523b260652b38f2c5e0fc991830abd94732 100644 --- a/src/ui/QGCToolBar.cc +++ b/src/ui/QGCToolBar.cc @@ -24,6 +24,7 @@ This file is part of the QGROUNDCONTROL project #include #include #include +#include "SerialLink.h" #include "QGCToolBar.h" #include "UASManager.h" #include "MainWindow.h" @@ -145,11 +146,6 @@ void QGCToolBar::createUI() toolBarWpLabel->setAlignment(Qt::AlignCenter); addWidget(toolBarWpLabel); - toolBarDistLabel = new QLabel(this); - toolBarDistLabel->setToolTip(tr("Distance to current waypoint")); - toolBarDistLabel->setAlignment(Qt::AlignCenter); - addWidget(toolBarDistLabel); - toolBarMessageLabel = new QLabel(this); toolBarMessageLabel->setToolTip(tr("Most recent system message")); toolBarMessageLabel->setObjectName("toolBarMessageLabel"); @@ -159,6 +155,27 @@ void QGCToolBar::createUI() spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); addWidget(spacer); + portComboBox = new QComboBox(this); + portComboBox->setToolTip(tr("Choose the COM port to use")); + portComboBox->setEnabled(true); + portComboBox->setMinimumWidth(200); + addWidget(portComboBox); + + baudcomboBox = new QComboBox(this); + baudcomboBox->setToolTip(tr("Choose what baud rate to use")); + baudcomboBox->setEnabled(true); + baudcomboBox->setMinimumWidth(80); + baudcomboBox->addItem("9600"); + baudcomboBox->addItem("14400"); + baudcomboBox->addItem("19200"); + baudcomboBox->addItem("38400"); + baudcomboBox->addItem("57600"); + baudcomboBox->addItem("115200"); + baudcomboBox->setCurrentIndex(5); + addWidget(baudcomboBox); + + + connectButton = new QPushButton(tr("Connect"), this); connectButton->setObjectName("connectButton"); connectButton->setToolTip(tr("Connect wireless link to MAV")); @@ -210,7 +227,6 @@ void QGCToolBar::resetToolbarUI() toolBarBatteryBar->setDisabled(true); toolBarBatteryVoltageLabel->setText("xx.x V"); toolBarWpLabel->setText("WP--"); - toolBarDistLabel->setText("--- ---- m"); toolBarMessageLabel->clear(); lastSystemMessage = ""; lastSystemMessageTimeMs = 0; @@ -232,9 +248,13 @@ void QGCToolBar::setPerspectiveChangeActions(const QList &actions) first->setToolTip(actions.first()->toolTip()); first->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); first->setCheckable(true); + connect(first, SIGNAL(clicked(bool)), actions.first(), SIGNAL(triggered(bool))); connect(actions.first(),SIGNAL(triggered(bool)),first,SLOT(setChecked(bool))); + first->setObjectName("firstAction"); + + //first->setStyleSheet("QToolButton { min-height: 24px; max-height: 24px; min-width: 60px; color: #222222; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #A2A3A4, stop: 1 #B6B7B8); margin-left: 8px; margin-right: 0px; padding-left: 4px; padding-right: 8px; border-radius: 0px; border : 0px solid blue; border-bottom-left-radius: 6px; border-top-left-radius: 6px; border-left: 1px solid #484848; border-top: 1px solid #484848; border-bottom: 1px solid #484848; } QToolButton:checked { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #555555, stop: 1 #787878); color: #DDDDDD; }"); addWidget(first); group->addButton(first); @@ -357,7 +377,6 @@ void QGCToolBar::setActiveUAS(UASInterface* active) toolBarTimeoutAction->setVisible(false); toolBarMessageLabel->clear(); lastSystemMessageTimeMs = 0; - toolBarDistLabel->clear(); toolBarBatteryBar->setEnabled(true); setSystemType(mav, mav->getSystemType()); } @@ -379,9 +398,6 @@ void QGCToolBar::updateArmingState(bool armed) void QGCToolBar::updateView() { if (!changed) return; - //toolBarDistLabel->setText(tr("%1 m").arg(wpDistance, 6, 'f', 2, '0')); - // XXX add also rel altitude - toolBarDistLabel->setText(QString("%1 m MSL").arg(altitudeMSL, 6, 'f', 2, '0')); toolBarWpLabel->setText(tr("WP%1").arg(wpId)); toolBarBatteryBar->setValue(batteryPercent); if (batteryPercent < 30 && toolBarBatteryBar->value() >= 30) { @@ -454,6 +470,7 @@ void QGCToolBar::updateBatteryRemaining(UASInterface* uas, double voltage, doubl Q_UNUSED(uas); Q_UNUSED(seconds); Q_UNUSED(current); + if (batteryPercent != percent || batteryVoltage != voltage) changed = true; batteryPercent = percent; batteryVoltage = voltage; @@ -579,12 +596,15 @@ void QGCToolBar::addLink(LinkInterface* link) connect(currentLink, SIGNAL(connected(bool)), this, SLOT(updateLinkState(bool))); updateLinkState(link->isConnected()); } + updateComboBox(); } void QGCToolBar::removeLink(LinkInterface* link) { if (link == currentLink) { currentLink = NULL; + //portComboBox->setEnabled(false); + //portComboBox->clear(); // XXX magic number if (LinkManager::instance()->getLinks().count() > 2) { currentLink = LinkManager::instance()->getLinks().last(); @@ -593,6 +613,32 @@ void QGCToolBar::removeLink(LinkInterface* link) connectButton->setText(tr("New Link")); } } + updateComboBox(); +} +void QGCToolBar::updateComboBox() +{ + portComboBox->clear(); + for (int i=0;igetLinks().count();i++) + { + SerialLink *slink = qobject_cast(LinkManager::instance()->getLinks()[i]); + if (slink) + { + //It's a serial link + QList portlist = slink->getCurrentPorts(); + //if (!slink->isConnected()) + //{ + for (int j=0;jaddItem("Serial port:" + QString::number(i) + ":" + portlist[j]); + } + //} + //We only really want to display from unconnected sources. + } + else + { + portComboBox->addItem(LinkManager::instance()->getLinks()[i]->getName()); + } + } } void QGCToolBar::updateLinkState(bool connected) @@ -622,7 +668,23 @@ void QGCToolBar::connectLink(bool connect) { MainWindow::instance()->addLink(); } else if (connect) { - LinkManager::instance()->getLinks().last()->connect(); + if (portComboBox->currentText().split(":").count()>2) + { + int linknum = portComboBox->currentText().split(":")[1].toInt(); + SerialLink *link = qobject_cast(LinkManager::instance()->getLinks().at(linknum)); + if (link) + { + QString portname = portComboBox->currentText().split(":")[2]; + link->setPortName(portname.trimmed()); + } + int baud = baudcomboBox->currentText().toInt(); + link->setBaudRate(baud); + link->connect(); + } + else + { + LinkManager::instance()->getLinks().last()->connect(); + } } else if (!connect && LinkManager::instance()->getLinks().count() > 2) { LinkManager::instance()->getLinks().last()->disconnect(); } diff --git a/src/ui/QGCToolBar.h b/src/ui/QGCToolBar.h index ac7141ff02f3141871db6c0eeecb0a470aee848d..dd2a5bf2e0beec80b5150b79e8454203c33b0e16 100644 --- a/src/ui/QGCToolBar.h +++ b/src/ui/QGCToolBar.h @@ -30,6 +30,7 @@ This file is part of the QGROUNDCONTROL project #include #include #include +#include #include "UASInterface.h" #include "QGCMAVLinkLogPlayer.h" @@ -88,7 +89,7 @@ protected: void loadSettings(); void createUI(); void resetToolbarUI(); - + void updateComboBox(); UASInterface* mav; QLabel* symbolLabel; QLabel* toolBarNameLabel; @@ -98,11 +99,14 @@ protected: QLabel* toolBarModeLabel; QLabel* toolBarStateLabel; QLabel* toolBarWpLabel; - QLabel* toolBarDistLabel; QLabel* toolBarMessageLabel; QPushButton* connectButton; QProgressBar* toolBarBatteryBar; QLabel* toolBarBatteryVoltageLabel; + + QGCMAVLinkLogPlayer* player; + QComboBox *portComboBox; + QComboBox *baudcomboBox; bool changed; float batteryPercent; float batteryVoltage; diff --git a/src/ui/QGCVehicleConfig.cc b/src/ui/QGCVehicleConfig.cc index b99535bccbaf2a24a9f17f2eef59dbe199c4b036..d94076dbd48b464a9384f6e40741c781a87be03e 100644 --- a/src/ui/QGCVehicleConfig.cc +++ b/src/ui/QGCVehicleConfig.cc @@ -1525,14 +1525,14 @@ void QGCVehicleConfig::updateView() ui->throttleWidget->setValue(rcValue[2]); ui->yawWidget->setValue(rcValue[3]); - ui->rollWidget->setMin(rcMin[0]); - ui->rollWidget->setMax(rcMax[0]); - ui->pitchWidget->setMin(rcMin[1]); - ui->pitchWidget->setMax(rcMax[1]); - ui->throttleWidget->setMin(rcMin[2]); - ui->throttleWidget->setMax(rcMax[2]); - ui->yawWidget->setMin(rcMin[3]); - ui->yawWidget->setMax(rcMax[3]); + ui->rollWidget->setMin(800); + ui->rollWidget->setMax(2200); + ui->pitchWidget->setMin(800); + ui->pitchWidget->setMax(2200); + ui->throttleWidget->setMin(800); + ui->throttleWidget->setMax(2200); + ui->yawWidget->setMin(800); + ui->yawWidget->setMax(2200); } ui->chanLabel->setText(QString("%1/%2").arg(rcValue[rcMapping[0]]).arg(rcRoll, 5, 'f', 2, QChar(' '))); diff --git a/src/ui/SerialConfigurationWindow.cc b/src/ui/SerialConfigurationWindow.cc index 499188ea2d5d5c459d10eac3657cdfac88672e89..72974c7c14fa039da95cbc857f3a8d7d8367d908 100644 --- a/src/ui/SerialConfigurationWindow.cc +++ b/src/ui/SerialConfigurationWindow.cc @@ -216,23 +216,23 @@ void SerialConfigurationWindow::setupPortList() if (!link) return; // Get the ports available on this system - QVector* ports = link->getCurrentPorts(); + QList ports = link->getCurrentPorts(); QString storedName = this->link->getPortName(); bool storedFound = false; // Add the ports in reverse order, because we prepend them to the list - for (int i = ports->size() - 1; i >= 0; --i) + for (int i = ports.count() - 1; i >= 0; --i) { // Prepend newly found port to the list - if (ui.portName->findText(ports->at(i)) == -1) + if (ui.portName->findText(ports[i]) == -1) { - ui.portName->insertItem(0, ports->at(i)); - if (!userConfigured) ui.portName->setEditText(ports->at(i)); + ui.portName->insertItem(0, ports[i]); + if (!userConfigured) ui.portName->setEditText(ports[i]); } // Check if the stored link name is still present - if (ports->at(i).contains(storedName) || storedName.contains(ports->at(i))) + if (ports[i].contains(storedName) || storedName.contains(ports[i])) storedFound = true; } @@ -259,7 +259,7 @@ void SerialConfigurationWindow::setParityNone(bool accept) void SerialConfigurationWindow::setParityOdd(bool accept) { - if (accept) link->setParityType(1); + if (accept) link->setParityType(1); // [TODO] This needs to be Fixed [BB] } void SerialConfigurationWindow::setParityEven(bool accept) diff --git a/src/ui/UASRawStatusView.cpp b/src/ui/UASRawStatusView.cpp index 51c48191bf33379445777da242058d91bb014dbc..ca0ac37003d1eebaf5d5a9a0d6b0fa8aa6c0fed0 100644 --- a/src/ui/UASRawStatusView.cpp +++ b/src/ui/UASRawStatusView.cpp @@ -16,7 +16,7 @@ UASRawStatusView::UASRawStatusView(QWidget *parent) : QWidget(parent) // FIXME reinstate once fixed. - //timer->start(2000); + timer->start(2000); } void UASRawStatusView::addSource(MAVLinkDecoder *decoder) { @@ -122,6 +122,7 @@ void UASRawStatusView::updateTableTimerTick() //We're over what we can do. Add a column and continue. columncount+=2; broke = true; + i = valueMap.constEnd(); // Ensure loop breakout. break; } } diff --git a/src/ui/XbeeConfigurationWindow.cpp b/src/ui/XbeeConfigurationWindow.cpp index 7be847ac651f6300758dc7ee8355238d5803045c..72104bffd966b65cd69d67a0a754bf826bf202bf 100644 --- a/src/ui/XbeeConfigurationWindow.cpp +++ b/src/ui/XbeeConfigurationWindow.cpp @@ -8,7 +8,8 @@ #include #ifdef _WIN32 -#include +//#include +#include #endif #if defined (__APPLE__) && defined (__MACH__) @@ -368,11 +369,12 @@ void XbeeConfigurationWindow::setupPortList() #ifdef _WIN32 // Get the ports available on this system - QList ports = QextSerialEnumerator::getPorts(); + QList ports = QSerialPortInfo::availablePorts(); + //QList ports = QextSerialEnumerator::getPorts(); // Add the ports in reverse order, because we prepend them to the list for (int i = ports.size() - 1; i >= 0; i--) { - QString portString = QString(ports.at(i).portName.toLocal8Bit().constData()) + " - " + QString(ports.at(i).friendName.toLocal8Bit().constData()).split("(").first(); + QString portString = QString(ports.at(i).portName().toLocal8Bit().constData()); // Prepend newly found port to the list if (portBox->findText(portString) == -1) { portBox->insertItem(0, portString); diff --git a/src/ui/apmtoolbar.cpp b/src/ui/apmtoolbar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42e85ddc91a83a19e7797a53fa7fb694e6ce9f06 --- /dev/null +++ b/src/ui/apmtoolbar.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include "LinkManager.h" +#include "MainWindow.h" + +#include "apmtoolbar.h" + +APMToolBar::APMToolBar(QWidget *parent): + QDeclarativeView(parent) +{ + // Configure our QML object + setSource(QUrl::fromLocalFile("qml/ApmToolBar.qml")); + setResizeMode(QDeclarativeView::SizeRootObjectToView); + this->rootContext()->setContextProperty("globalObj", this); + connect(LinkManager::instance(),SIGNAL(newLink(LinkInterface*)), + this, SLOT(updateLinkDisplay(LinkInterface*))); + + if (LinkManager::instance()->getLinks().count()>=3) { + updateLinkDisplay(LinkManager::instance()->getLinks().last()); + } + + setConnection(false); +} + +void APMToolBar::setFlightViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerFlightView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setFlightPlanViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerFlightPlanView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setHardwareViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerHardwareView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setSoftwareViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerSoftwareView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setSimulationViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerSimulationView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setTerminalViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerTerminalView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setConnectMAVAction(QAction *action) +{ + connect(this, SIGNAL(connectMAV()), action, SIGNAL(triggered())); +} + +void APMToolBar::selectFlightView() +{ + qDebug() << "APMToolBar: SelectFlightView"; + emit triggerFlightView(); +} + +void APMToolBar::selectFlightPlanView() +{ + qDebug() << "APMToolBar: SelectFlightPlanView"; + emit triggerFlightPlanView(); +} + +void APMToolBar::selectHardwareView() +{ + qDebug() << "APMToolBar: selectHardwareView"; + emit triggerHardwareView(); +} + +void APMToolBar::selectSoftwareView() +{ + qDebug() << "APMToolBar: selectSoftwareView"; + emit triggerSoftwareView(); +} + +void APMToolBar::selectSimulationView() +{ + qDebug() << "APMToolBar: selectSimulationView"; +} + +void APMToolBar::selectTerminalView() +{ + qDebug() << "APMToolBar: selectTerminalView"; +} + +void APMToolBar::connectMAV() +{ + qDebug() << "APMToolBar: connectMAV "; + + bool connected = LinkManager::instance()->getLinks().last()->isConnected(); + bool result; + + if (!connected && LinkManager::instance()->getLinks().count() < 3) + { + // No Link so prompt to connect one + MainWindow::instance()->addLink(); + } else if (!connected) { + // Need to Connect Link + result = LinkManager::instance()->getLinks().last()->connect(); + + } else if (connected && LinkManager::instance()->getLinks().count() > 2) { + // result need to be the opposite of success. + result = !LinkManager::instance()->getLinks().last()->disconnect(); + } + qDebug() << "result = " << result; + + // Change the image to represent the state + setConnection(result); + + emit MAVConnected(result); +} + +void APMToolBar::setConnection(bool connection) +{ + // Change the image to represent the state + QObject *object = rootObject(); + object->setProperty("connected", connection); +} + +APMToolBar::~APMToolBar() +{ + qDebug() << "Destory APM Toolbar"; +} + +void APMToolBar::showConnectionDialog() +{ + // Displays a UI where the user can select a MAV Link. + qDebug() << "APMToolBar: showConnectionDialog link count =" + << LinkManager::instance()->getLinks().count(); + + LinkInterface *link = LinkManager::instance()->getLinks().last(); + bool result; + + if (link && LinkManager::instance()->getLinks().count() >= 3) + { + // Serial Link so prompt to config it + connect(link, SIGNAL(updateLink(LinkInterface*)), + this, SLOT(updateLinkDisplay(LinkInterface*))); + result = MainWindow::instance()->configLink(link); + + if (!result) + qDebug() << "Link Config Failed!"; + } else { + // No Link so prompt to create one + MainWindow::instance()->addLink(); + } + +} + +void APMToolBar::updateLinkDisplay(LinkInterface* newLink) +{ + qDebug() << "APMToolBar: updateLinkDisplay"; + QObject *object = rootObject(); + + if (newLink && object){ + qint64 baudrate = newLink->getNominalDataRate(); + object->setProperty("baudrateLabel", QString::number(baudrate)); + + QString linkName = newLink->getName(); + object->setProperty("linkNameLabel", linkName); + + connect(newLink, SIGNAL(connected(bool)), + this, SLOT(setConnection(bool))); + + setConnection(newLink->isConnected()); + } +} diff --git a/src/ui/apmtoolbar.h b/src/ui/apmtoolbar.h new file mode 100644 index 0000000000000000000000000000000000000000..d4e48212e54460e07638a07d00b0286637d82359 --- /dev/null +++ b/src/ui/apmtoolbar.h @@ -0,0 +1,49 @@ +#ifndef APMTOOLBAR_H +#define APMTOOLBAR_H + +#include +#include + +class LinkInterface; + +class APMToolBar : public QDeclarativeView +{ + Q_OBJECT +public: + explicit APMToolBar(QWidget *parent = 0); + ~APMToolBar(); + + void setFlightViewAction(QAction *action); + void setFlightPlanViewAction(QAction *action); + void setHardwareViewAction(QAction *action); + void setSoftwareViewAction(QAction *action); + void setSimulationViewAction(QAction *action); + void setTerminalViewAction(QAction *action); + void setConnectMAVAction(QAction *action); + +signals: + void triggerFlightView(); + void triggerFlightPlanView(); + void triggerHardwareView(); + void triggerSoftwareView(); + void triggerSimulationView(); + void triggerTerminalView(); + + void MAVConnected(bool connected); + +public slots: + void selectFlightView(); + void selectFlightPlanView(); + void selectHardwareView(); + void selectSoftwareView(); + void selectSimulationView(); + void selectTerminalView(); + + void connectMAV(); + void showConnectionDialog(); + void setConnection(bool connection); + + void updateLinkDisplay(LinkInterface *newLink); +}; + +#endif // APMTOOLBAR_H diff --git a/src/ui/configuration/AP2ConfigWidget.cc b/src/ui/configuration/AP2ConfigWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..08eb44f21568c68f25dad68eca89f75a8b559b87 --- /dev/null +++ b/src/ui/configuration/AP2ConfigWidget.cc @@ -0,0 +1,29 @@ +#include +#include "AP2ConfigWidget.h" + +AP2ConfigWidget::AP2ConfigWidget(QWidget *parent) : QWidget(parent) +{ + m_uas = 0; + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + activeUASSet(UASManager::instance()->getActiveUAS()); +} +void AP2ConfigWidget::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(parameterChanged(int,int,QString,QVariant)),this,SLOT(parameterChanged(int,int,QString,QVariant))); + m_uas = 0; + } + if (!uas) return; + m_uas = uas; + connect(m_uas,SIGNAL(parameterChanged(int,int,QString,QVariant)),this,SLOT(parameterChanged(int,int,QString,QVariant))); +} + +void AP2ConfigWidget::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + +} +void AP2ConfigWidget::showNullMAVErrorMessageBox() +{ + QMessageBox::information(0,tr("Error"),tr("Please connect to a MAV before attempting to set configuration")); +} diff --git a/src/ui/configuration/AP2ConfigWidget.h b/src/ui/configuration/AP2ConfigWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..69e9f6f7fb0d21c02740324216718bc44281df03 --- /dev/null +++ b/src/ui/configuration/AP2ConfigWidget.h @@ -0,0 +1,22 @@ +#ifndef AP2CONFIGWIDGET_H +#define AP2CONFIGWIDGET_H + +#include +#include "UASManager.h" +#include "UASInterface.h" +class AP2ConfigWidget : public QWidget +{ + Q_OBJECT +public: + explicit AP2ConfigWidget(QWidget *parent = 0); +protected: + UASInterface *m_uas; + void showNullMAVErrorMessageBox(); +signals: + +public slots: + virtual void activeUASSet(UASInterface *uas); + virtual void parameterChanged(int uas, int component, QString parameterName, QVariant value); +}; + +#endif // AP2CONFIGWIDGET_H diff --git a/src/ui/configuration/AccelCalibrationConfig.cc b/src/ui/configuration/AccelCalibrationConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..945ba5e2e09fdc0322975756ecac80e4213dc5db --- /dev/null +++ b/src/ui/configuration/AccelCalibrationConfig.cc @@ -0,0 +1,98 @@ +#include "AccelCalibrationConfig.h" + + +AccelCalibrationConfig::AccelCalibrationConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.calibrateAccelButton,SIGNAL(clicked()),this,SLOT(calibrateButtonClicked())); + + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + activeUASSet(UASManager::instance()->getActiveUAS()); + m_accelAckCount=0; +} + +AccelCalibrationConfig::~AccelCalibrationConfig() +{ +} +void AccelCalibrationConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(uasTextMessageReceived(int,int,int,QString))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(m_uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(uasTextMessageReceived(int,int,int,QString))); + +} + +void AccelCalibrationConfig::calibrateButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (m_accelAckCount == 0) + { + MAV_CMD command = MAV_CMD_PREFLIGHT_CALIBRATION; + int confirm = 0; + float param1 = 0.0; + float param2 = 0.0; + float param3 = 0.0; + float param4 = 0.0; + float param5 = 1.0; + float param6 = 0.0; + float param7 = 0.0; + int component = 1; + m_uas->executeCommand(command, confirm, param1, param2, param3, param4, param5, param6, param7, component); + } + else if (m_accelAckCount <= 5) + { + m_uas->executeCommandAck(m_accelAckCount++,true); + } + else + { + m_uas->executeCommandAck(m_accelAckCount++,true); + ui.calibrateAccelButton->setText("Calibrate\nAccelerometer"); + } + +} +void AccelCalibrationConfig::uasTextMessageReceived(int uasid, int componentid, int severity, QString text) +{ + //command received: " Severity 1 + //Place APM Level and press any key" severity 5 + if (severity == 5) + { + //This is a calibration instruction + if (m_accelAckCount == 0) + { + //Calibration Sucessful\r" + ui.calibrateAccelButton->setText("Any\nKey"); + m_accelAckCount++; + } + if (m_accelAckCount == 7) + { + //All finished + //ui.outputLabel->setText(ui.outputLabel->text() + "\n" + text); + ui.outputLabel->setText(text); + m_accelAckCount++; + } + if (m_accelAckCount == 8) + { + if (text.contains("Calibration") && text.contains("successful")) + { + m_accelAckCount = 0; + } + ui.outputLabel->setText(ui.outputLabel->text() + "\n" + text); + } + else + { + ui.outputLabel->setText(text); + } + } + +} diff --git a/src/ui/configuration/AccelCalibrationConfig.h b/src/ui/configuration/AccelCalibrationConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..ef6f6e1a17a50236368553c62490ca9a98965e92 --- /dev/null +++ b/src/ui/configuration/AccelCalibrationConfig.h @@ -0,0 +1,26 @@ +#ifndef ACCELCALIBRATIONCONFIG_H +#define ACCELCALIBRATIONCONFIG_H + +#include +#include "ui_AccelCalibrationConfig.h" +#include "UASManager.h" +#include "UASInterface.h" +#include "AP2ConfigWidget.h" + +class AccelCalibrationConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AccelCalibrationConfig(QWidget *parent = 0); + ~AccelCalibrationConfig(); +private slots: + void activeUASSet(UASInterface *uas); + void calibrateButtonClicked(); + void uasTextMessageReceived(int uasid, int componentid, int severity, QString text); +private: + int m_accelAckCount; + Ui::AccelCalibrationConfig ui; +}; + +#endif // ACCELCALIBRATIONCONFIG_H diff --git a/src/ui/configuration/AccelCalibrationConfig.ui b/src/ui/configuration/AccelCalibrationConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6555a572584b14a77a048a68d7d8cb0a2ccd2c13 --- /dev/null +++ b/src/ui/configuration/AccelCalibrationConfig.ui @@ -0,0 +1,62 @@ + + + AccelCalibrationConfig + + + + 0 + 0 + 576 + 354 + + + + Form + + + + + 10 + 0 + 231 + 31 + + + + <h2>Accelerometer Calibration</h2> + + + false + + + + + + 70 + 160 + 111 + 41 + + + + Calibrate +Accelerometer + + + + + + 20 + 50 + 311 + 101 + + + + + + + + + + diff --git a/src/ui/configuration/AdvParameterList.cc b/src/ui/configuration/AdvParameterList.cc new file mode 100644 index 0000000000000000000000000000000000000000..971f290e615ccfe4ffd2dd61ccc8995e9640460c --- /dev/null +++ b/src/ui/configuration/AdvParameterList.cc @@ -0,0 +1,53 @@ +#include "AdvParameterList.h" + + +AdvParameterList::AdvParameterList(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.tableWidget->setColumnCount(4); + ui.tableWidget->horizontalHeader()->hide(); + ui.tableWidget->verticalHeader()->hide(); + ui.tableWidget->setColumnWidth(0,200); + ui.tableWidget->setColumnWidth(1,100); + ui.tableWidget->setColumnWidth(2,200); + ui.tableWidget->setColumnWidth(3,800); + +} + +AdvParameterList::~AdvParameterList() +{ +} +void AdvParameterList::setParameterMetaData(QString name,QString humanname,QString description) +{ + m_paramToNameMap[name] = humanname; + m_paramToDescriptionMap[name] = description; +} + +void AdvParameterList::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + + if (!m_paramValueMap.contains(parameterName)) + { + ui.tableWidget->setRowCount(ui.tableWidget->rowCount()+1); + if (m_paramToNameMap.contains(parameterName)) + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,0,new QTableWidgetItem(m_paramToNameMap[parameterName])); + } + else + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,0,new QTableWidgetItem("Unknown")); + } + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,1,new QTableWidgetItem(QString::number(value.toFloat(),'f',2))); + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,2,new QTableWidgetItem(parameterName)); + if (m_paramToDescriptionMap.contains(parameterName)) + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,3,new QTableWidgetItem(m_paramToDescriptionMap[parameterName])); + } + else + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,3,new QTableWidgetItem("Unknown")); + } + m_paramValueMap[parameterName] = ui.tableWidget->item(ui.tableWidget->rowCount()-1,1); + } + m_paramValueMap[parameterName]->setText(QString::number(value.toFloat(),'f',2)); +} diff --git a/src/ui/configuration/AdvParameterList.h b/src/ui/configuration/AdvParameterList.h new file mode 100644 index 0000000000000000000000000000000000000000..6ff55a22ff28b105f82f780436805539a88d3628 --- /dev/null +++ b/src/ui/configuration/AdvParameterList.h @@ -0,0 +1,25 @@ +#ifndef ADVPARAMETERLIST_H +#define ADVPARAMETERLIST_H + +#include +#include "ui_AdvParameterList.h" +#include "AP2ConfigWidget.h" + +class AdvParameterList : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AdvParameterList(QWidget *parent = 0); + void setParameterMetaData(QString name,QString humanname,QString description); + ~AdvParameterList(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap m_paramValueMap; + QMap m_paramToNameMap; + QMap m_paramToDescriptionMap; + Ui::AdvParameterList ui; +}; + +#endif // ADVPARAMETERLIST_H diff --git a/src/ui/configuration/AdvParameterList.ui b/src/ui/configuration/AdvParameterList.ui new file mode 100644 index 0000000000000000000000000000000000000000..9b9d40849b5392d85b9da2e490ad3fe1a1f5ccdb --- /dev/null +++ b/src/ui/configuration/AdvParameterList.ui @@ -0,0 +1,31 @@ + + + AdvParameterList + + + + 0 + 0 + 666 + 497 + + + + Form + + + + + + <h2>Advanced Parameter List</h2> + + + + + + + + + + + diff --git a/src/ui/configuration/AdvancedParamConfig.cc b/src/ui/configuration/AdvancedParamConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..8410b6a002a0a4021096108c31f854a194ca711e --- /dev/null +++ b/src/ui/configuration/AdvancedParamConfig.cc @@ -0,0 +1,35 @@ +#include "AdvancedParamConfig.h" + + +AdvancedParamConfig::AdvancedParamConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); +} + +AdvancedParamConfig::~AdvancedParamConfig() +{ +} +void AdvancedParamConfig::addRange(QString title,QString description,QString param,double min,double max) +{ + ParamWidget *widget = new ParamWidget(ui.scrollAreaWidgetContents); + m_paramToWidgetMap[param] = widget; + widget->setupDouble(title + "(" + param + ")",description,0,min,max); + ui.verticalLayout->addWidget(widget); + widget->show(); +} + +void AdvancedParamConfig::addCombo(QString title,QString description,QString param,QList > valuelist) +{ + ParamWidget *widget = new ParamWidget(ui.scrollAreaWidgetContents); + m_paramToWidgetMap[param] = widget; + widget->setupCombo(title + "(" + param + ")",description,valuelist); + ui.verticalLayout->addWidget(widget); + widget->show(); +} +void AdvancedParamConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_paramToWidgetMap.contains(parameterName)) + { + m_paramToWidgetMap[parameterName]->setValue(value.toDouble()); + } +} diff --git a/src/ui/configuration/AdvancedParamConfig.h b/src/ui/configuration/AdvancedParamConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..6d52ede4cdc194285590f47760bce096ec14a02e --- /dev/null +++ b/src/ui/configuration/AdvancedParamConfig.h @@ -0,0 +1,24 @@ +#ifndef ADVANCEDPARAMCONFIG_H +#define ADVANCEDPARAMCONFIG_H + +#include +#include "ui_AdvancedParamConfig.h" +#include "AP2ConfigWidget.h" +#include "ParamWidget.h" +class AdvancedParamConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AdvancedParamConfig(QWidget *parent = 0); + ~AdvancedParamConfig(); + void addRange(QString title,QString description,QString param,double min,double max); + void addCombo(QString title,QString description,QString param,QList > valuelist); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap m_paramToWidgetMap; + Ui::AdvancedParamConfig ui; +}; + +#endif // ADVANCEDPARAMCONFIG_H diff --git a/src/ui/configuration/AdvancedParamConfig.ui b/src/ui/configuration/AdvancedParamConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..596861a3a2aeb2ea2792cc74ea184cf89ee3dae1 --- /dev/null +++ b/src/ui/configuration/AdvancedParamConfig.ui @@ -0,0 +1,50 @@ + + + AdvancedParamConfig + + + + 0 + 0 + 725 + 632 + + + + Form + + + + + + <h2>Advanced Params</h2> + + + + + + + true + + + + + 0 + 0 + 705 + 585 + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/AirspeedConfig.cc b/src/ui/configuration/AirspeedConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..b5c91f33b7c1ce6cfe95816e064d86b4d3ca105b --- /dev/null +++ b/src/ui/configuration/AirspeedConfig.cc @@ -0,0 +1,82 @@ +#include "AirspeedConfig.h" +#include + +AirspeedConfig::AirspeedConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + connect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); +} + +AirspeedConfig::~AirspeedConfig() +{ +} +void AirspeedConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "ARSPD_ENABLE") + { + if (value.toInt() == 0) + { + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.enableCheckBox->setChecked(false); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setEnabled(false); + } + else + { + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.enableCheckBox->setChecked(true); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setEnabled(true); + } + } + else if (parameterName == "ARSPD_USE") + { + if (value.toInt() == 0) + { + disconnect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setChecked(false); + connect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + } + else + { + disconnect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setChecked(true); + connect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + } + } +} + +void AirspeedConfig::useCheckBoxClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->getParamManager()->setParameter(1,"ARSPD_USE",1); + } + else + { + m_uas->getParamManager()->setParameter(1,"ARSPD_USE",0); + } +} + +void AirspeedConfig::enableCheckBoxClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->getParamManager()->setParameter(1,"ARSPD_ENABLE",1); + } + else + { + m_uas->getParamManager()->setParameter(1,"ARSPD_ENABLE",0); + } +} diff --git a/src/ui/configuration/AirspeedConfig.h b/src/ui/configuration/AirspeedConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..1646b36759fa0154eb23120203edc0873ead70bc --- /dev/null +++ b/src/ui/configuration/AirspeedConfig.h @@ -0,0 +1,23 @@ +#ifndef AIRSPEEDCONFIG_H +#define AIRSPEEDCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_AirspeedConfig.h" + +class AirspeedConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AirspeedConfig(QWidget *parent = 0); + ~AirspeedConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void useCheckBoxClicked(bool checked); + void enableCheckBoxClicked(bool checked); +private: + Ui::AirspeedConfig ui; +}; + +#endif // AIRSPEEDCONFIG_H diff --git a/src/ui/configuration/AirspeedConfig.ui b/src/ui/configuration/AirspeedConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..7d33cae3664b7dec1d1e5ce1bbf64beca2735ed7 --- /dev/null +++ b/src/ui/configuration/AirspeedConfig.ui @@ -0,0 +1,82 @@ + + + AirspeedConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>Airspeed</h2> + + + false + + + + + + 20 + 60 + 71 + 71 + + + + + + + :/files/images/devices/BR-0004-03-2.jpg + + + true + + + + + + 110 + 70 + 70 + 17 + + + + Enable + + + + + + 110 + 100 + 91 + 17 + + + + Use Airspeed + + + + + + + + diff --git a/src/ui/configuration/AntennaTrackerConfig.cc b/src/ui/configuration/AntennaTrackerConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..6b406da474fe3a268c47a42eee4255ca83f4c037 --- /dev/null +++ b/src/ui/configuration/AntennaTrackerConfig.cc @@ -0,0 +1,11 @@ +#include "AntennaTrackerConfig.h" + + +AntennaTrackerConfig::AntennaTrackerConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +AntennaTrackerConfig::~AntennaTrackerConfig() +{ +} diff --git a/src/ui/configuration/AntennaTrackerConfig.h b/src/ui/configuration/AntennaTrackerConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..35271cb288b08e58252f7599c6f65cee07062017 --- /dev/null +++ b/src/ui/configuration/AntennaTrackerConfig.h @@ -0,0 +1,19 @@ +#ifndef ANTENNATRACKERCONFIG_H +#define ANTENNATRACKERCONFIG_H + +#include +#include "ui_AntennaTrackerConfig.h" + +class AntennaTrackerConfig : public QWidget +{ + Q_OBJECT + +public: + explicit AntennaTrackerConfig(QWidget *parent = 0); + ~AntennaTrackerConfig(); + +private: + Ui::AntennaTrackerConfig ui; +}; + +#endif // ANTENNATRACKERCONFIG_H diff --git a/src/ui/configuration/AntennaTrackerConfig.ui b/src/ui/configuration/AntennaTrackerConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..f355fc4ca95baf26f51d6789540354c27152e04d --- /dev/null +++ b/src/ui/configuration/AntennaTrackerConfig.ui @@ -0,0 +1,311 @@ + + + AntennaTrackerConfig + + + + 0 + 0 + 1171 + 560 + + + + Form + + + + + 20 + 10 + 151 + 31 + + + + <h2>Antenna Tracker</h2> + + + false + + + + + + 20 + 50 + 46 + 13 + + + + Interface + + + + + + 80 + 50 + 69 + 22 + + + + + + + 160 + 50 + 69 + 22 + + + + + + + 240 + 50 + 69 + 22 + + + + + + + 320 + 50 + 75 + 23 + + + + Connect + + + + + + 20 + 80 + 581 + 131 + + + + Pan + + + + + + + + + + Angle + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Center PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + + + + + + + + Trim + + + Qt::AlignCenter + + + + + + + -180 + + + 0 + + + Qt::Horizontal + + + + + + + 0 + + + Qt::AlignCenter + + + + + + + + + Rev + + + + + + + + + + + 20 + 220 + 581 + 131 + + + + Tilt + + + + + + + + + + Angle + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Center PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + + + + + + + + Trim + + + Qt::AlignCenter + + + + + + + -180 + + + 180 + + + Qt::Horizontal + + + + + + + 0 + + + Qt::AlignCenter + + + + + + + + + Rev + + + + + + + + + + + diff --git a/src/ui/configuration/ApmHardwareConfig.cc b/src/ui/configuration/ApmHardwareConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..225f6a1f2b3794494cfce3e6d5f206abd3ce2f13 --- /dev/null +++ b/src/ui/configuration/ApmHardwareConfig.cc @@ -0,0 +1,187 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief APM Hardware Configuration widget source. + * + * @author Michael Carpenter + * + */ +#include "ApmHardwareConfig.h" + +ApmHardwareConfig::ApmHardwareConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); + + + ui.manditoryHardware->setVisible(false); + ui.frameTypeButton->setVisible(false); + ui.compassButton->setVisible(false); + ui.accelCalibrateButton->setVisible(false); + ui.arduPlaneLevelButton->setVisible(false); + ui.radioCalibrateButton->setVisible(false); + ui.optionalHardwareButton->setVisible(false); + ui.batteryMonitorButton->setVisible(false); + ui.sonarButton->setVisible(false); + ui.airspeedButton->setVisible(false); + ui.opticalFlowButton->setVisible(false); + ui.osdButton->setVisible(false); + ui.cameraGimbalButton->setVisible(false); + + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.radio3DRButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.batteryMonitorButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.sonarButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.opticalFlowButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.osdButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.cameraGimbalButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.antennaTrackerButton,SLOT(setShown(bool))); + + connect(ui.frameTypeButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + + QWidget *widget = new QWidget(this); + ui.stackedWidget->addWidget(widget); //Firmware placeholder. + m_buttonToConfigWidgetMap[ui.firmwareButton] = widget; + connect(ui.firmwareButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_frameConfig = new FrameTypeConfig(this); + ui.stackedWidget->addWidget(m_frameConfig); + m_buttonToConfigWidgetMap[ui.frameTypeButton] = m_frameConfig; + connect(ui.frameTypeButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_compassConfig = new CompassConfig(this); + ui.stackedWidget->addWidget(m_compassConfig); + m_buttonToConfigWidgetMap[ui.compassButton] = m_compassConfig; + connect(ui.compassButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_accelConfig = new AccelCalibrationConfig(this); + ui.stackedWidget->addWidget(m_accelConfig); + m_buttonToConfigWidgetMap[ui.accelCalibrateButton] = m_accelConfig; + connect(ui.accelCalibrateButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_planeLevel = new ApmPlaneLevel(this); + ui.stackedWidget->addWidget(m_planeLevel); + m_buttonToConfigWidgetMap[ui.arduPlaneLevelButton] = m_planeLevel; + connect(ui.arduPlaneLevelButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_radioConfig = new RadioCalibrationConfig(this); + ui.stackedWidget->addWidget(m_radioConfig); + m_buttonToConfigWidgetMap[ui.radioCalibrateButton] = m_radioConfig; + connect(ui.radioCalibrateButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + + m_radio3drConfig = new Radio3DRConfig(this); + ui.stackedWidget->addWidget(m_radio3drConfig); + m_buttonToConfigWidgetMap[ui.radio3DRButton] = m_radio3drConfig; + connect(ui.radio3DRButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_batteryConfig = new BatteryMonitorConfig(this); + ui.stackedWidget->addWidget(m_batteryConfig); + m_buttonToConfigWidgetMap[ui.batteryMonitorButton] = m_batteryConfig; + connect(ui.batteryMonitorButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_sonarConfig = new SonarConfig(this); + ui.stackedWidget->addWidget(m_sonarConfig); + m_buttonToConfigWidgetMap[ui.sonarButton] = m_sonarConfig; + connect(ui.sonarButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_airspeedConfig = new AirspeedConfig(this); + ui.stackedWidget->addWidget(m_airspeedConfig); + m_buttonToConfigWidgetMap[ui.airspeedButton] = m_airspeedConfig; + connect(ui.airspeedButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_opticalFlowConfig = new OpticalFlowConfig(this); + ui.stackedWidget->addWidget(m_opticalFlowConfig); + m_buttonToConfigWidgetMap[ui.opticalFlowButton] = m_opticalFlowConfig; + connect(ui.opticalFlowButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_osdConfig = new OsdConfig(this); + ui.stackedWidget->addWidget(m_osdConfig); + m_buttonToConfigWidgetMap[ui.osdButton] = m_osdConfig; + connect(ui.osdButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_cameraGimbalConfig = new CameraGimbalConfig(this); + ui.stackedWidget->addWidget(m_cameraGimbalConfig); + m_buttonToConfigWidgetMap[ui.cameraGimbalButton] = m_cameraGimbalConfig; + connect(ui.cameraGimbalButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_antennaTrackerConfig = new AntennaTrackerConfig(this); + ui.stackedWidget->addWidget(m_antennaTrackerConfig); + m_buttonToConfigWidgetMap[ui.antennaTrackerButton] = m_antennaTrackerConfig; + connect(ui.antennaTrackerButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + if (UASManager::instance()->getActiveUAS()) + { + activeUASSet(UASManager::instance()->getActiveUAS()); + } +} +void ApmHardwareConfig::activateStackedWidget() +{ + if (m_buttonToConfigWidgetMap.contains(sender())) + { + ui.stackedWidget->setCurrentWidget(m_buttonToConfigWidgetMap[sender()]); + } +} + +ApmHardwareConfig::~ApmHardwareConfig() +{ +} + +void ApmHardwareConfig::activeUASSet(UASInterface *uas) +{ + if (!uas) + { + return; + } + if (uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.arduPlaneLevelButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.airspeedButton,SLOT(setShown(bool))); + } + else if (uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.frameTypeButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.accelCalibrateButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + } + else if (uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + } + else + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + } + ui.firmwareButton->setVisible(true); + ui.manditoryHardware->setVisible(true); + ui.manditoryHardware->setChecked(true); + ui.optionalHardwareButton->setVisible(true); + ui.optionalHardwareButton->setChecked(true); +} diff --git a/src/ui/configuration/ApmHardwareConfig.h b/src/ui/configuration/ApmHardwareConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..aea82cde735fff99c1640b52e2a6daadff37d1cc --- /dev/null +++ b/src/ui/configuration/ApmHardwareConfig.h @@ -0,0 +1,85 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief APM Hardware Configuration widget header. + * + * @author Michael Carpenter + * + */ + +#ifndef APMHARDWARECONFIG_H +#define APMHARDWARECONFIG_H + +#include +#include "ui_ApmHardwareConfig.h" +#include +#include +#include "FrameTypeConfig.h" +#include "CompassConfig.h" +#include "AccelCalibrationConfig.h" +#include "RadioCalibrationConfig.h" +#include "Radio3DRConfig.h" +#include "BatteryMonitorConfig.h" +#include "SonarConfig.h" +#include "AirspeedConfig.h" +#include "OpticalFlowConfig.h" +#include "OsdConfig.h" +#include "CameraGimbalConfig.h" +#include "AntennaTrackerConfig.h" +#include "ApmPlaneLevel.h" + +class ApmHardwareConfig : public QWidget +{ + Q_OBJECT + +public: + explicit ApmHardwareConfig(QWidget *parent = 0); + ~ApmHardwareConfig(); +private: + FrameTypeConfig *m_frameConfig; + CompassConfig *m_compassConfig; + AccelCalibrationConfig *m_accelConfig; + RadioCalibrationConfig *m_radioConfig; + + Radio3DRConfig *m_radio3drConfig; + BatteryMonitorConfig *m_batteryConfig; + SonarConfig *m_sonarConfig; + AirspeedConfig *m_airspeedConfig; + OpticalFlowConfig *m_opticalFlowConfig; + OsdConfig *m_osdConfig; + CameraGimbalConfig *m_cameraGimbalConfig; + AntennaTrackerConfig *m_antennaTrackerConfig; + ApmPlaneLevel *m_planeLevel; +private slots: + void activeUASSet(UASInterface *uas); + void activateStackedWidget(); +private: + Ui::ApmHardwareConfig ui; + + //This is a map between the buttons, and the widgets they should be displying + QMap m_buttonToConfigWidgetMap; +}; + +#endif // APMHARDWARECONFIG_H diff --git a/src/ui/configuration/ApmHardwareConfig.ui b/src/ui/configuration/ApmHardwareConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..e4a711b060d08d3c1cb58b395d54e9341587cb41 --- /dev/null +++ b/src/ui/configuration/ApmHardwareConfig.ui @@ -0,0 +1,330 @@ + + + ApmHardwareConfig + + + + 0 + 0 + 1225 + 827 + + + + Form + + + + + 0 + 20 + 175 + 531 + + + + + 175 + 0 + + + + + 175 + 16777215 + + + + true + + + + + 0 + 0 + 156 + 676 + + + + + + + QLayout::SetMinAndMaxSize + + + + + + 100 + 35 + + + + Install Firmware + + + + + + + + 0 + 35 + + + + >>> Manditory Hardware + + + true + + + + + + + + 0 + 35 + + + + Qt::LeftToRight + + + Frame Type + + + + + + + + 0 + 35 + + + + Compass + + + + + + + + 0 + 35 + + + + Qt::LeftToRight + + + false + + + Accel Calibration + + + + + + + + 0 + 35 + + + + Qt::LeftToRight + + + false + + + ArduPlane Level + + + + + + + + 100 + 35 + + + + + 16777215 + 16777215 + + + + Radio Calibration + + + false + + + false + + + + + + + + 0 + 35 + + + + >>> Optional Hardware + + + true + + + + + + + + 0 + 35 + + + + 3DR Radio + + + + + + + + 0 + 35 + + + + Battery Monitor + + + + + + + + 0 + 35 + + + + Sonar + + + + + + + + 0 + 35 + + + + Airspeed + + + + + + + + 0 + 35 + + + + Optical Flow + + + + + + + + 0 + 35 + + + + OSD + + + + + + + + 0 + 35 + + + + Camera Gimbal + + + + + + + + 0 + 35 + + + + Antenna Tracker + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 200 + 30 + 921 + 761 + + + + -1 + + + + + + diff --git a/src/ui/configuration/ApmPlaneLevel.cc b/src/ui/configuration/ApmPlaneLevel.cc new file mode 100644 index 0000000000000000000000000000000000000000..c93193055f32c823853b53fd6cb68d335d909683 --- /dev/null +++ b/src/ui/configuration/ApmPlaneLevel.cc @@ -0,0 +1,65 @@ +#include "ApmPlaneLevel.h" +#include + +ApmPlaneLevel::ApmPlaneLevel(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.levelPushButton,SIGNAL(clicked()),this,SLOT(levelClicked())); + connect(ui.manualLevelCheckBox,SIGNAL(toggled(bool)),this,SLOT(manualCheckBoxToggled(bool))); +} + +ApmPlaneLevel::~ApmPlaneLevel() +{ +} +void ApmPlaneLevel::levelClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + QMessageBox::information(0,"Warning","Be sure the plane is completly level, then click ok"); + MAV_CMD command = MAV_CMD_PREFLIGHT_CALIBRATION; + int confirm = 0; + float param1 = 1.0; + float param2 = 0.0; + float param3 = 1.0; + float param4 = 0.0; + float param5 = 0.0; + float param6 = 0.0; + float param7 = 0.0; + int component = 1; + m_uas->executeCommand(command, confirm, param1, param2, param3, param4, param5, param6, param7, component); + QMessageBox::information(0,"Warning","Leveling completed"); +} + +void ApmPlaneLevel::manualCheckBoxToggled(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->getParamManager()->setParameter(1,"MANUAL_LEVEL",1); + } + else + { + m_uas->getParamManager()->setParameter(1,"MANUAL_LEVEL",0); + } +} +void ApmPlaneLevel::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "MANUAL_LEVEL") + { + if (value.toInt() == 1) + { + ui.manualLevelCheckBox->setChecked(true); + } + else + { + ui.manualLevelCheckBox->setChecked(false); + } + } +} diff --git a/src/ui/configuration/ApmPlaneLevel.h b/src/ui/configuration/ApmPlaneLevel.h new file mode 100644 index 0000000000000000000000000000000000000000..a6a38078f3704b10a283126fc84a6aebfe8738bd --- /dev/null +++ b/src/ui/configuration/ApmPlaneLevel.h @@ -0,0 +1,23 @@ +#ifndef APMPLANELEVEL_H +#define APMPLANELEVEL_H + +#include +#include "ui_ApmPlaneLevel.h" +#include "AP2ConfigWidget.h" + +class ApmPlaneLevel : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ApmPlaneLevel(QWidget *parent = 0); + ~ApmPlaneLevel(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void levelClicked(); + void manualCheckBoxToggled(bool checked); +private: + Ui::ApmPlaneLevel ui; +}; + +#endif // APMPLANELEVEL_H diff --git a/src/ui/configuration/ApmPlaneLevel.ui b/src/ui/configuration/ApmPlaneLevel.ui new file mode 100644 index 0000000000000000000000000000000000000000..ef22b19992f262acf776e84fbfca097e2074c997 --- /dev/null +++ b/src/ui/configuration/ApmPlaneLevel.ui @@ -0,0 +1,99 @@ + + + ApmPlaneLevel + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 10 + 10 + 141 + 31 + + + + <h2>ArduPlane Level</h2> + + + + + + 50 + 70 + 271 + 41 + + + + By Default your plane will autolevel on every boot. +To disable this action you need to turn on manual +level and perform a level to calibrate the accel offsets. + + + + + + 50 + 150 + 291 + 16 + + + + Level your plane and click Level to set default accel offsets + + + + + + 160 + 180 + 75 + 23 + + + + Level + + + + + + 120 + 230 + 151 + 51 + + + + For advanced users ONLY + + + + + 30 + 20 + 91 + 17 + + + + Manual Level + + + + + + + diff --git a/src/ui/configuration/ApmSoftwareConfig.cc b/src/ui/configuration/ApmSoftwareConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..fabc49139b3b18a3c8c9b38ee3866db9f0679741 --- /dev/null +++ b/src/ui/configuration/ApmSoftwareConfig.cc @@ -0,0 +1,359 @@ +#include +#include +#include + +#include "ApmSoftwareConfig.h" + + +ApmSoftwareConfig::ApmSoftwareConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); + + ui.flightModesButton->setVisible(false); + ui.standardParamButton->setVisible(false); + ui.failSafeButton->setVisible(false); + ui.advancedParamButton->setVisible(false); + ui.advParamListButton->setVisible(false); + ui.arduCopterPidButton->setVisible(false); + ui.arduRoverPidButton->setVisible(false); + ui.arduPlanePidButton->setVisible(false); + + m_flightConfig = new FlightModeConfig(this); + ui.stackedWidget->addWidget(m_flightConfig); + m_buttonToConfigWidgetMap[ui.flightModesButton] = m_flightConfig; + connect(ui.flightModesButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_standardParamConfig = new StandardParamConfig(this); + ui.stackedWidget->addWidget(m_standardParamConfig); + m_buttonToConfigWidgetMap[ui.standardParamButton] = m_standardParamConfig; + connect(ui.standardParamButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_failSafeConfig = new FailSafeConfig(this); + ui.stackedWidget->addWidget(m_failSafeConfig); + m_buttonToConfigWidgetMap[ui.failSafeButton] = m_failSafeConfig; + connect(ui.failSafeButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_advancedParamConfig = new AdvancedParamConfig(this); + ui.stackedWidget->addWidget(m_advancedParamConfig); + m_buttonToConfigWidgetMap[ui.advancedParamButton] = m_advancedParamConfig; + connect(ui.advancedParamButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_advParameterList = new AdvParameterList(this); + ui.stackedWidget->addWidget(m_advParameterList); + m_buttonToConfigWidgetMap[ui.advParamListButton] = m_advParameterList; + connect(ui.advParamListButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_arduCopterPidConfig = new ArduCopterPidConfig(this); + ui.stackedWidget->addWidget(m_arduCopterPidConfig); + m_buttonToConfigWidgetMap[ui.arduCopterPidButton] = m_arduCopterPidConfig; + connect(ui.arduCopterPidButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_arduPlanePidConfig = new ArduPlanePidConfig(this); + ui.stackedWidget->addWidget(m_arduPlanePidConfig); + m_buttonToConfigWidgetMap[ui.arduPlanePidButton] = m_arduPlanePidConfig; + connect(ui.arduPlanePidButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_arduRoverPidConfig = new ArduRoverPidConfig(this); + ui.stackedWidget->addWidget(m_arduRoverPidConfig); + m_buttonToConfigWidgetMap[ui.arduRoverPidButton] = m_arduRoverPidConfig; + connect(ui.arduRoverPidButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + activeUASSet(UASManager::instance()->getActiveUAS()); +} + +ApmSoftwareConfig::~ApmSoftwareConfig() +{ +} +void ApmSoftwareConfig::activateStackedWidget() +{ + if (m_buttonToConfigWidgetMap.contains(sender())) + { + ui.stackedWidget->setCurrentWidget(m_buttonToConfigWidgetMap[sender()]); + } +} +void ApmSoftwareConfig::activeUASSet(UASInterface *uas) +{ + if (!uas) + { + return; + } + + ui.flightModesButton->setVisible(true); + ui.standardParamButton->setVisible(true); + ui.failSafeButton->setVisible(true); + ui.advancedParamButton->setVisible(true); + ui.advParamListButton->setVisible(true); + + if (uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + ui.arduPlanePidButton->setVisible(true); + ui.arduCopterPidButton->setVisible(false); + ui.arduRoverPidButton->setVisible(false); + } + else if (uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + ui.arduCopterPidButton->setVisible(true); + ui.arduPlanePidButton->setVisible(false); + ui.arduRoverPidButton->setVisible(false); + } + else if (uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + ui.arduRoverPidButton->setVisible(true); + ui.arduCopterPidButton->setVisible(false); + ui.arduPlanePidButton->setVisible(false); + } + + + QDir autopilotdir(qApp->applicationDirPath() + "/files/" + uas->getAutopilotTypeName().toLower()); + QFile xmlfile(autopilotdir.absolutePath() + "/arduplane.pdef.xml"); + if (xmlfile.exists() && !xmlfile.open(QIODevice::ReadOnly)) + { + return; + } + + QXmlStreamReader xml(xmlfile.readAll()); + xmlfile.close(); + + //TODO: Testing to ensure that incorrectly formated XML won't break this. + //Also, move this into the Param Manager, as it should handle all metadata. + while (!xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "paramfile") + { + xml.readNext(); + while ((xml.name() != "paramfile") && !xml.atEnd()) + { + QString valuetype = ""; + if (xml.isStartElement() && (xml.name() == "vehicles" || xml.name() == "libraries")) //Enter into the vehicles loop + { + valuetype = xml.name().toString(); + xml.readNext(); + while ((xml.name() != valuetype) && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "parameters") //This is a parameter block + { + QString parametersname = ""; + if (xml.attributes().hasAttribute("name")) + { + parametersname = xml.attributes().value("name").toString(); + } + QVariantMap genset; + QVariantMap advset; + + QString setname = parametersname; + xml.readNext(); + int genarraycount = 0; + int advarraycount = 0; + while ((xml.name() != "parameters") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "param") + { + QString humanname = xml.attributes().value("humanName").toString(); + QString name = xml.attributes().value("name").toString(); + QString tab= xml.attributes().value("user").toString(); + if (tab == "Advanced") + { + advset["title"] = parametersname; + } + else + { + genset["title"] = parametersname; + } + if (name.contains(":")) + { + name = name.split(":")[1]; + } + QString docs = xml.attributes().value("documentation").toString(); + //paramTooltips[name] = name + " - " + docs; + + int type = -1; //Type of item + QMap fieldmap; + QMap valuemap; + xml.readNext(); + while ((xml.name() != "param") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "values") + { + type = 1; //1 is a combobox + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "TYPE"] = "COMBO"; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_DESCRIPTION"] = humanname; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID"] = name; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COMPONENTID"] = 1; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "TYPE"] = "COMBO"; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_DESCRIPTION"] = humanname; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID"] = name; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COMPONENTID"] = 1; + } + int paramcount = 0; + xml.readNext(); + while ((xml.name() != "values") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "value") + { + + QString code = xml.attributes().value("code").toString(); + QString arg = xml.readElementText(); + valuemap[code] = arg; + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_TEXT"] = arg; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_VAL"] = code.toInt(); + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_TEXT"] = arg; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_VAL"] = code.toInt(); + } + paramcount++; + } + xml.readNext(); + } + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COUNT"] = paramcount; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COUNT"] = paramcount; + } + } + if (xml.isStartElement() && xml.name() == "field") + { + type = 2; //2 is a slider + QString fieldtype = xml.attributes().value("name").toString(); + QString text = xml.readElementText(); + fieldmap[fieldtype] = text; + } + xml.readNext(); + } + if (type == -1) + { + //Nothing inside! Assume it's a value, give it a default range. + type = 2; + QString fieldtype = "Range"; + QString text = "0 100"; //TODO: Determine a better way of figuring out default ranges. + fieldmap[fieldtype] = text; + } + if (type == 2) + { + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "TYPE"] = "SLIDER"; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_DESCRIPTION"] = humanname; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_PARAMID"] = name; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_COMPONENTID"] = 1; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "TYPE"] = "SLIDER"; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_DESCRIPTION"] = humanname; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_PARAMID"] = name; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_COMPONENTID"] = 1; + } + if (fieldmap.contains("Range")) + { + float min = 0; + float max = 0; + //Some range fields list "0-10" and some list "0 10". Handle both. + if (fieldmap["Range"].split(" ").size() > 1) + { + min = fieldmap["Range"].split(" ")[0].trimmed().toFloat(); + max = fieldmap["Range"].split(" ")[1].trimmed().toFloat(); + } + else if (fieldmap["Range"].split("-").size() > 1) + { + min = fieldmap["Range"].split("-")[0].trimmed().toFloat(); + max = fieldmap["Range"].split("-")[1].trimmed().toFloat(); + } + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_MIN"] = min; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_MAX"] = max; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_MIN"] = min; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_MAX"] = max; + } + } + } + if (tab == "Advanced") + { + advarraycount++; + advset["count"] = advarraycount; + } + else + { + genarraycount++; + genset["count"] = genarraycount; + } + //Right here we have a single param in memory + if (valuemap.size() > 0) + { + QList > valuelist; + for (QMap::const_iterator i = valuemap.constBegin();i!=valuemap.constEnd();i++) + { + valuelist.append(QPair(i.key().toInt(),i.value())); + } + if (tab == "Standard") + { + m_standardParamConfig->addCombo(humanname,docs,name,valuelist); + } + else if (tab == "Advanced") + { + m_advancedParamConfig->addCombo(humanname,docs,name,valuelist); + } + m_advParameterList->setParameterMetaData(name,humanname,docs); + } + else if (fieldmap.size() > 0) + { + float min = 0; + float max = 100; + if (fieldmap.contains("Range")) + { + float min = 0; + float max = 0; + //Some range fields list "0-10" and some list "0 10". Handle both. + if (fieldmap["Range"].split(" ").size() > 1) + { + min = fieldmap["Range"].split(" ")[0].trimmed().toFloat(); + max = fieldmap["Range"].split(" ")[1].trimmed().toFloat(); + } + else if (fieldmap["Range"].split("-").size() > 1) + { + min = fieldmap["Range"].split("-")[0].trimmed().toFloat(); + max = fieldmap["Range"].split("-")[1].trimmed().toFloat(); + } + } + if (tab == "Standard") + { + m_standardParamConfig->addRange(humanname,docs,name,min,max); + } + else if (tab == "Advanced") + { + m_advancedParamConfig->addRange(humanname,docs,name,max,min); + } + m_advParameterList->setParameterMetaData(name,humanname,docs); + } + + } + xml.readNext(); + } + } + xml.readNext(); + } + + } + xml.readNext(); + } + } + xml.readNext(); + } + +} diff --git a/src/ui/configuration/ApmSoftwareConfig.h b/src/ui/configuration/ApmSoftwareConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..c4eabf414e6055b83d81f23d04baa458d81e2883 --- /dev/null +++ b/src/ui/configuration/ApmSoftwareConfig.h @@ -0,0 +1,44 @@ +#ifndef APMSOFTWARECONFIG_H +#define APMSOFTWARECONFIG_H + +#include +#include "ui_ApmSoftwareConfig.h" +#include "FlightModeConfig.h" +#include "BasicPidConfig.h" +#include "StandardParamConfig.h" +#include "GeoFenceConfig.h" +#include "FailSafeConfig.h" +#include "AdvancedParamConfig.h" +#include "ArduCopterPidConfig.h" +#include "ArduPlanePidConfig.h" +#include "ArduRoverPidConfig.h" +#include "AdvParameterList.h" +#include "UASInterface.h" +#include "UASManager.h" + +class ApmSoftwareConfig : public QWidget +{ + Q_OBJECT + +public: + explicit ApmSoftwareConfig(QWidget *parent = 0); + ~ApmSoftwareConfig(); +private slots: + void activateStackedWidget(); + void activeUASSet(UASInterface *uas); +private: + Ui::ApmSoftwareConfig ui; + BasicPidConfig *m_basicPidConfig; + FlightModeConfig *m_flightConfig; + StandardParamConfig *m_standardParamConfig; + GeoFenceConfig *m_geoFenceConfig; + FailSafeConfig *m_failSafeConfig; + AdvancedParamConfig *m_advancedParamConfig; + ArduCopterPidConfig *m_arduCopterPidConfig; + ArduPlanePidConfig *m_arduPlanePidConfig; + ArduRoverPidConfig *m_arduRoverPidConfig; + AdvParameterList *m_advParameterList; + QMap m_buttonToConfigWidgetMap; +}; + +#endif // APMSOFTWARECONFIG_H diff --git a/src/ui/configuration/ApmSoftwareConfig.ui b/src/ui/configuration/ApmSoftwareConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..219d2c6de7bd9e7eced610045ad3cc1ee80346d9 --- /dev/null +++ b/src/ui/configuration/ApmSoftwareConfig.ui @@ -0,0 +1,210 @@ + + + ApmSoftwareConfig + + + + 0 + 0 + 853 + 619 + + + + Form + + + + + + + 175 + 0 + + + + + 175 + 16777215 + + + + true + + + + + 0 + 0 + 173 + 599 + + + + + + + QLayout::SetMinAndMaxSize + + + + + + 100 + 35 + + + + qgroundcontrol 2.0 Config + + + + + + + + 0 + 35 + + + + Flight Modes + + + false + + + + + + + + 0 + 35 + + + + Standard Params + + + false + + + + + + + + 0 + 35 + + + + FailSafe + + + false + + + + + + + + 0 + 35 + + + + Advanced Params + + + false + + + + + + + + 0 + 35 + + + + Adv Parameter List + + + false + + + + + + + + 0 + 35 + + + + ArduCopter Pids + + + false + + + + + + + + 0 + 35 + + + + ArduPlane Pids + + + + + + + + 0 + 35 + + + + ArduRover Pids + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/ArduCopterPidConfig.cc b/src/ui/configuration/ArduCopterPidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd0924323b10d67e2888e5a736f1fa5349080a75 --- /dev/null +++ b/src/ui/configuration/ArduCopterPidConfig.cc @@ -0,0 +1,182 @@ +#include "ArduCopterPidConfig.h" + +ArduCopterPidConfig::ArduCopterPidConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + m_nameToBoxMap["STB_RLL_P"] = ui.stabilPitchPSpinBox; + m_nameToBoxMap["STB_PIT_P"] = ui.stabilRollPSpinBox; + m_nameToBoxMap["STB_YAW_P"] = ui.stabilYawPSpinBox; + m_nameToBoxMap["HLD_LAT_P"] = ui.loiterPidPSpinBox; + + m_nameToBoxMap["RATE_RLL_P"] = ui.rateRollPSpinBox; + m_nameToBoxMap["RATE_RLL_I"] = ui.rateRollISpinBox; + m_nameToBoxMap["RATE_RLL_D"] = ui.rateRollDSpinBox; + m_nameToBoxMap["RATE_RLL_IMAX"] = ui.rateRollIMAXSpinBox; + + m_nameToBoxMap["RATE_PIT_P"] = ui.ratePitchPSpinBox; + m_nameToBoxMap["RATE_PIT_I"] = ui.ratePitchISpinBox; + m_nameToBoxMap["RATE_PIT_D"] = ui.ratePitchDSpinBox; + m_nameToBoxMap["RATE_PIT_IMAX"] = ui.ratePitchIMAXSpinBox; + + m_nameToBoxMap["RATE_YAW_P"] = ui.rateYawPSpinBox; + m_nameToBoxMap["RATE_YAW_I"] = ui.rateYawISpinBox; + m_nameToBoxMap["RATE_YAW_D"] = ui.rateYawDSpinBox; + m_nameToBoxMap["RATE_YAW_IMAX"] = ui.rateYawIMAXSpinBox; + + m_nameToBoxMap["LOITER_LAT_P"] = ui.rateLoiterPSpinBox; + m_nameToBoxMap["LOITER_LAT_I"] = ui.rateLoiterISpinBox; + m_nameToBoxMap["LOITER_LAT_D"] = ui.rateLoiterDSpinBox; + m_nameToBoxMap["LOITER_LAT_IMAX"] = ui.rateLoiterIMAXSpinBox; + + m_nameToBoxMap["THR_ACCEL_P"] = ui.throttleAccelPSpinBox; + m_nameToBoxMap["THR_ACCEL_I"] = ui.throttleAccelISpinBox; + m_nameToBoxMap["THR_ACCEL_D"] = ui.throttleAccelDSpinBox; + m_nameToBoxMap["THR_ACCEL_IMAX"] = ui.throttleAccelIMAXSpinBox; + + m_nameToBoxMap["THR_RATE_P"] = ui.throttleRatePSpinBox; + m_nameToBoxMap["THR_RATE_D"] = ui.throttleDateDSpinBox; + + m_nameToBoxMap["THR_ALT_P"] = ui.altitudeHoldPSpinBox; + + m_nameToBoxMap["WPNAV_SPEED"] = ui.wpNavLoiterSpeedSpinBox; + m_nameToBoxMap["WPNAV_RADIUS"] = ui.wpNavRadiusSpinBox; + m_nameToBoxMap["WPNAV_SPEED_DN"] = ui.wpNavSpeedDownSpinBox; + m_nameToBoxMap["WPNAV_LOIT_SPEED"] = ui.wpNavSpeedSpinBox; + m_nameToBoxMap["WPNAV_SPEED_UP"] = ui.wpNavSpeedUpSpinBox; + + m_nameToBoxMap["TUNE_HIGH"] = ui.ch6MaxSpinBox; + m_nameToBoxMap["TUNE_LOW"] = ui.ch6MinSpinBox; + + connect(ui.writePushButton,SIGNAL(clicked()),this,SLOT(writeButtonClicked())); + connect(ui.refreshPushButton,SIGNAL(clicked()),this,SLOT(refreshButtonClicked())); + + + + m_ch6ValueToTextList.append(QPair(0,"CH6_NONE")); + m_ch6ValueToTextList.append(QPair(1,"CH6_STABILIZE_KP")); + m_ch6ValueToTextList.append(QPair(2,"CH6_STABILIZE_KI")); + m_ch6ValueToTextList.append(QPair(3,"CH6_YAW_KP")); + m_ch6ValueToTextList.append(QPair(24,"CH6_YAW_KI")); + m_ch6ValueToTextList.append(QPair(4,"CH6_RATE_KP")); + m_ch6ValueToTextList.append(QPair(5,"CH6_RATE_KI")); + m_ch6ValueToTextList.append(QPair(6,"CH6_YAW_RATE_KP")); + m_ch6ValueToTextList.append(QPair(26,"CH6_YAW_RATE_KD")); + m_ch6ValueToTextList.append(QPair(7,"CH6_THROTTLE_KP")); + m_ch6ValueToTextList.append(QPair(9,"CH6_RELAY")); + m_ch6ValueToTextList.append(QPair(10,"CH6_WP_SPEED")); + m_ch6ValueToTextList.append(QPair(12,"CH6_LOITER_KP")); + m_ch6ValueToTextList.append(QPair(13,"CH6_HELI_EXTERNAL_GYRO")); + m_ch6ValueToTextList.append(QPair(14,"CH6_THR_HOLD_KP")); + m_ch6ValueToTextList.append(QPair(17,"CH6_OPTFLOW_KP")); + m_ch6ValueToTextList.append(QPair(18,"CH6_OPTFLOW_KI")); + m_ch6ValueToTextList.append(QPair(19,"CH6_OPTFLOW_KD")); + m_ch6ValueToTextList.append(QPair(21,"CH6_RATE_KD")); + m_ch6ValueToTextList.append(QPair(22,"CH6_LOITER_RATE_KP")); + m_ch6ValueToTextList.append(QPair(23,"CH6_LOITER_RATE_KD")); + m_ch6ValueToTextList.append(QPair(25,"CH6_ACRO_KP")); + m_ch6ValueToTextList.append(QPair(27,"CH6_LOITER_KI")); + m_ch6ValueToTextList.append(QPair(28,"CH6_LOITER_RATE_KI")); + m_ch6ValueToTextList.append(QPair(29,"CH6_STABILIZE_KD")); + m_ch6ValueToTextList.append(QPair(30,"CH6_AHRS_YAW_KP")); + m_ch6ValueToTextList.append(QPair(31,"CH6_AHRS_KP")); + m_ch6ValueToTextList.append(QPair(32,"CH6_INAV_TC")); + m_ch6ValueToTextList.append(QPair(33,"CH6_THROTTLE_KI")); + m_ch6ValueToTextList.append(QPair(34,"CH6_THR_ACCEL_KP")); + m_ch6ValueToTextList.append(QPair(35,"CH6_THR_ACCEL_KI")); + m_ch6ValueToTextList.append(QPair(36,"CH6_THR_ACCEL_KD")); + m_ch6ValueToTextList.append(QPair(38,"CH6_DECLINATION")); + m_ch6ValueToTextList.append(QPair(39,"CH6_CIRCLE_RATE")); + for (int i=0;iaddItem(m_ch6ValueToTextList[i].second); + } + + m_ch78ValueToTextList.append(QPair(0,"Do nothing")); + m_ch78ValueToTextList.append(QPair(2,"Flip")); + m_ch78ValueToTextList.append(QPair(3,"Simple mode")); + m_ch78ValueToTextList.append(QPair(4,"RTL")); + m_ch78ValueToTextList.append(QPair(5,"Save Trim")); + m_ch78ValueToTextList.append(QPair(7,"Save WP")); + m_ch78ValueToTextList.append(QPair(8,"Multi Mode")); + m_ch78ValueToTextList.append(QPair(9,"Camera Trigger")); + m_ch78ValueToTextList.append(QPair(10,"Sonar")); + m_ch78ValueToTextList.append(QPair(11,"Fence")); + m_ch78ValueToTextList.append(QPair(12,"ResetToArmedYaw")); + for (int i=0;iaddItem(m_ch78ValueToTextList[i].second); + ui.ch8OptComboBox->addItem(m_ch78ValueToTextList[i].second); + } +} + +ArduCopterPidConfig::~ArduCopterPidConfig() +{ +} +void ArduCopterPidConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_nameToBoxMap.contains(parameterName)) + { + m_nameToBoxMap[parameterName]->setValue(value.toDouble()); + } + else if (parameterName == "TUNE") + { + for (int i=0;isetCurrentIndex(i); + } + } + } + else if (parameterName == "CH7_OPT") + { + for (int i=0;isetCurrentIndex(i); + } + } + } + else if (parameterName == "CH8_OPT") + { + for (int i=0;isetCurrentIndex(i); + } + } + } +} +void ArduCopterPidConfig::writeButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->setParameter(1,i.key(),i.value()->value()); + } + m_uas->getParamManager()->setParameter(1,"TUNE",m_ch78ValueToTextList[ui.ch6OptComboBox->currentIndex()].first); + m_uas->getParamManager()->setParameter(1,"CH7_OPT",m_ch78ValueToTextList[ui.ch7OptComboBox->currentIndex()].first); + m_uas->getParamManager()->setParameter(1,"CH8_OPT",m_ch78ValueToTextList[ui.ch8OptComboBox->currentIndex()].first); +} + +void ArduCopterPidConfig::refreshButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->requestParameterUpdate(1,i.key()); + } + m_uas->getParamManager()->requestParameterUpdate(1,"TUNE"); + m_uas->getParamManager()->requestParameterUpdate(1,"CH7_OPT"); + m_uas->getParamManager()->requestParameterUpdate(1,"CH8_OPT"); +} diff --git a/src/ui/configuration/ArduCopterPidConfig.h b/src/ui/configuration/ArduCopterPidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3ac3a693619c1f0d23bf11b0dee1ec3723da99 --- /dev/null +++ b/src/ui/configuration/ArduCopterPidConfig.h @@ -0,0 +1,27 @@ +#ifndef ARDUCOPTERPIDCONFIG_H +#define ARDUCOPTERPIDCONFIG_H + +#include +#include "ui_ArduCopterPidConfig.h" + +#include "AP2ConfigWidget.h" + +class ArduCopterPidConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ArduCopterPidConfig(QWidget *parent = 0); + ~ArduCopterPidConfig(); +private slots: + void writeButtonClicked(); + void refreshButtonClicked(); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QList > m_ch6ValueToTextList; + QList > m_ch78ValueToTextList; + QMap m_nameToBoxMap; + Ui::ArduCopterPidConfig ui; +}; + +#endif // ARDUCOPTERPIDCONFIG_H diff --git a/src/ui/configuration/ArduCopterPidConfig.ui b/src/ui/configuration/ArduCopterPidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..351ce51ed24e4463b9c9ac508fe2bea5c50730df --- /dev/null +++ b/src/ui/configuration/ArduCopterPidConfig.ui @@ -0,0 +1,1061 @@ + + + ArduCopterPidConfig + + + + 0 + 0 + 750 + 596 + + + + Form + + + + + 20 + 10 + 181 + 51 + + + + <h2>ArduCopter Pids</h2> + + + + + + 120 + 540 + 75 + 23 + + + + Write Params + + + + + + 220 + 540 + 91 + 23 + + + + Refresh Params + + + + + + 10 + 70 + 695 + 401 + + + + + + + Rate Yaw + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Loiter PID + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Rate Pitch + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Stabilize Roll + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Stabilize Pitch + + + + + + + + + + P + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + + + + + + + + Rate Roll + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Altitude Hold + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Stabilize Yaw + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Rate Loiter + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Lock Pitch and Roll Values + + + + + + + + + + + Ch6 Opt + + + + + + + + + + + + + + Min + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + Max + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Ch7 Opt + + + + + + + + + + + + + + Ch8 Opt + + + + + + + + + + + + + + Throttle Accel + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Throttle Rate + + + + + + + + + + P + + + + + + + D + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + WPNav (cm's) + + + + + + + + + + Speed + + + + + + + Radius + + + + + + + Speed Up + + + + + + + speed Down + + + + + + + Loiter Speed + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/ArduPlanePidConfig.cc b/src/ui/configuration/ArduPlanePidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..4cfa5efa6eeee1bdbd608c395e9aff96a6dfa737 --- /dev/null +++ b/src/ui/configuration/ArduPlanePidConfig.cc @@ -0,0 +1,99 @@ +#include "ArduPlanePidConfig.h" + + +ArduPlanePidConfig::ArduPlanePidConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + + m_nameToBoxMap["RLL2SRV_P"] = ui.servoRollPSpinBox; + m_nameToBoxMap["RLL2SRV_I"] = ui.servoRollISpinBox; + m_nameToBoxMap["RLL2SRV_D"] = ui.servoRollDSpinBox; + m_nameToBoxMap["RLL2SRV_IMAX"] = ui.servoRollIMAXSpinBox; + + m_nameToBoxMap["PTCH2SRV_P"] = ui.servoPitchPSpinBox; + m_nameToBoxMap["PTCH2SRV_I"] = ui.servoPitchISpinBox; + m_nameToBoxMap["PTCH2SRV_D"] = ui.servoPitchDSpinBox; + m_nameToBoxMap["PTCH2SRV_IMAX"] = ui.servoPitchIMAXSpinBox; + + m_nameToBoxMap["YW2SRV_P"] = ui.servoYawPSpinBox; + m_nameToBoxMap["YW2SRV_I"] = ui.servoYawISpinBox; + m_nameToBoxMap["YW2SRV_D"] = ui.servoYawDSpinBox; + m_nameToBoxMap["YW2SRV_IMAX"] = ui.servoYawIMAXSpinBox; + + m_nameToBoxMap["ALT2PTCH_P"] = ui.navAltPSpinBox; + m_nameToBoxMap["ALT2PTCH_I"] = ui.navAltISpinBox; + m_nameToBoxMap["ALT2PTCH_D"] = ui.navAltDSpinBox; + m_nameToBoxMap["ALT2PTCH_IMAX"] = ui.navAltIMAXSpinBox; + + m_nameToBoxMap["ARSP2PTCH_P"] = ui.navASPSpinBox; + m_nameToBoxMap["ARSP2PTCH_I"] = ui.navASISpinBox; + m_nameToBoxMap["ARSP2PTCH_D"] = ui.navASDSpinBox; + m_nameToBoxMap["ARSP2PTCH_IMAX"] = ui.navASIMAXSpinBox; + + m_nameToBoxMap["ENRGY2THR_P"] = ui.energyPSpinBox; + m_nameToBoxMap["ENRGY2THR_I"] = ui.energyISpinBox; + m_nameToBoxMap["ENRGY2THR_D"] = ui.energyDSpinBox; + m_nameToBoxMap["ENRGY2THR_IMAX"] = ui.energyIMAXSpinBox; + + m_nameToBoxMap["KFF_PTCH2THR"] = ui.otherPitchCompSpinBox; + m_nameToBoxMap["KFF_PTCHCOMP"] = ui.otherPtTSpinBox; + m_nameToBoxMap["KFF_RDDRMIX"] = ui.otherRudderMixSpinBox; + + m_nameToBoxMap["TRIM_THROTTLE"] = ui.throttleCruiseSpinBox; + m_nameToBoxMap["THR_FS_VALUE"] = ui.throttleFSSpinBox; + m_nameToBoxMap["THR_MAX"] = ui.throttleMaxSpinBox; + m_nameToBoxMap["THR_MIN"] = ui.throttleMinSpinBox; + + m_nameToBoxMap["TRIM_ARSPD_CM"] = ui.airspeedCruiseSpinBox; + m_nameToBoxMap["ARSPD_FBW_MAX"] = ui.airspeedFBWMaxSpinBox; + m_nameToBoxMap["ARSPD_FBW_MIN"] = ui.airspeedFBWMinSpinBox; + m_nameToBoxMap["ARSPD_RATIO"] = ui.airspeedRatioSpinBox; + + m_nameToBoxMap["NAVL1_DAMPING"] = ui.l1DampingSpinBox; + m_nameToBoxMap["NAVL1_PERIOD"] = ui.l1PeriodSpinBox; + + m_nameToBoxMap["LIM_ROLL_CD"] = ui.navBankMaxSpinBox; + m_nameToBoxMap["LIM_PITCH_MAX"] = ui.navPitchMaxSpinBox; + m_nameToBoxMap["LIM_PITCH_MIN"] = ui.navPitchMinSpinBox; + + connect(ui.writePushButton,SIGNAL(clicked()),this,SLOT(writeButtonClicked())); + connect(ui.refreshPushButton,SIGNAL(clicked()),this,SLOT(refreshButtonClicked())); + +} + +ArduPlanePidConfig::~ArduPlanePidConfig() +{ +} +void ArduPlanePidConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_nameToBoxMap.contains(parameterName)) + { + m_nameToBoxMap[parameterName]->setValue(value.toDouble()); + } +} +void ArduPlanePidConfig::writeButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->setParameter(1,i.key(),i.value()->value()); + } +} + +void ArduPlanePidConfig::refreshButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->requestParameterUpdate(1,i.key()); + } + +} diff --git a/src/ui/configuration/ArduPlanePidConfig.h b/src/ui/configuration/ArduPlanePidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..3a254cb37198ec3dcb85d75f03790aabb14cb78b --- /dev/null +++ b/src/ui/configuration/ArduPlanePidConfig.h @@ -0,0 +1,24 @@ +#ifndef ARDUPLANEPIDCONFIG_H +#define ARDUPLANEPIDCONFIG_H + +#include +#include "ui_ArduPlanePidConfig.h" +#include "AP2ConfigWidget.h" + +class ArduPlanePidConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ArduPlanePidConfig(QWidget *parent = 0); + ~ArduPlanePidConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void writeButtonClicked(); + void refreshButtonClicked(); +private: + QMap m_nameToBoxMap; + Ui::ArduPlanePidConfig ui; +}; + +#endif // ARDUPLANEPIDCONFIG_H diff --git a/src/ui/configuration/ArduPlanePidConfig.ui b/src/ui/configuration/ArduPlanePidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..4ee4c406b15f97f025969bdefc401c22fe9a3fd6 --- /dev/null +++ b/src/ui/configuration/ArduPlanePidConfig.ui @@ -0,0 +1,963 @@ + + + ArduPlanePidConfig + + + + 0 + 0 + 733 + 641 + + + + Form + + + + + 20 + 10 + 681 + 581 + + + + + + + L1 Control - Turn Control + + + + + + + + + + Period + + + + + + + Damping + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Servo Roll Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Nav Pitch Alt Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Nav Pitch AS Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Servo Yaw Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Throttle 0-100% + + + + + + + + + + Cruise + + + + + + + Min + + + + + + + Max + + + + + + + FS Value + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Servo Pitch Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Aiespeed m/s + + + + + + + + + + Cruise + + + + + + + FBW min + + + + + + + FBW max + + + + + + + Ratio + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 100.000000000000000 + + + + + + + + + + + + + + Other Mix's + + + + + + + + + + P to T + + + + + + + Pitch Comp + + + + + + + Rudder Mix + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + + + + + + + + Navigation Angles + + + + + + + + + + Bank Max + + + + + + + Pitch Max + + + + + + + Pitch Min + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + 10000.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + + + + Energy/Alt Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 100.000000000000000 + + + + + + + + + + + + + + + + 260 + 600 + 75 + 23 + + + + Write Params + + + + + + 350 + 600 + 75 + 23 + + + + Refresh Params + + + + + + diff --git a/src/ui/configuration/ArduRoverPidConfig.cc b/src/ui/configuration/ArduRoverPidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..f9d9034e671ab37fe1763a06ab0b5dc3333fca49 --- /dev/null +++ b/src/ui/configuration/ArduRoverPidConfig.cc @@ -0,0 +1,80 @@ +#include "ArduRoverPidConfig.h" + + +ArduRoverPidConfig::ArduRoverPidConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + nameToBoxMap["STEER2SRV_P"] = ui.steer2ServoPSpinBox; + nameToBoxMap["STEER2SRV_I"] = ui.steer2ServoISpinBox; + nameToBoxMap["STEER2SRV_D"] = ui.steer2ServoDSpinBox; + nameToBoxMap["STEER2SRV_IMAX"] = ui.steer2ServoIMAXSpinBox; + + nameToBoxMap["XTRK_ANGLE_CD"] = ui.xtrackEntryAngleSpinBox; + nameToBoxMap["XTRK_GAIN_SC"] = ui.xtrackGainSpinBox; + + nameToBoxMap["CRUISE_THROTTLE"] = ui.throttleCruiseSpinBox; + nameToBoxMap["THR_MIN"] = ui.throttleMinSpinBox; + nameToBoxMap["THR_MAX"] = ui.throttleMaxSpinBox; + nameToBoxMap["FS_THR_VALUE"] = ui.throttleFSSpinBox; + + nameToBoxMap["HDNG2STEER_P"] = ui.heading2SteerPSpinBox; + nameToBoxMap["HDNG2STEER_I"] = ui.heading2SteerISpinBox; + nameToBoxMap["HDNG2STEER_D"] = ui.heading2SteerDSpinBox; + nameToBoxMap["HDNG2STEER_IMAX"] = ui.heading2SteerIMAXSpinBox; + + nameToBoxMap["SPEED2THR_P"] = ui.speed2ThrottlePSpinBox; + nameToBoxMap["SPEED2THR_I"] = ui.speed2ThrottleISpinBox; + nameToBoxMap["SPEED2THR_D"] = ui.speed2ThrottleDSpinBox; + nameToBoxMap["SPEED2THR_IMAX"] = ui.speed2ThrottleIMAXSpinBox; + + nameToBoxMap["CRUISE_SPEED"] = ui.roverCruiseSpinBox; + nameToBoxMap["SPEED_TURN_GAIN"] = ui.roverTurnSpeedSpinBox; + nameToBoxMap["SPEED_TURN_DIST"] = ui.roverTurnDistSpinBox; + nameToBoxMap["WP_RADIUS"] = ui.roverWPRadiusSpinBox; + + nameToBoxMap["SONAR_TRIGGER_CM"] = ui.sonarTriggerSpinBox; + nameToBoxMap["SONAR_TURN_ANGLE"] = ui.sonarTurnAngleSpinBox; + nameToBoxMap["SONAR_TURN_TIME"] = ui.sonarTurnTimeSpinBox; + nameToBoxMap["SONAR_DEBOUNCE"] = ui.sonaeDebounceSpinBox; + + connect(ui.writePushButton,SIGNAL(clicked()),this,SLOT(writeButtonClicked())); + connect(ui.refreshPushButton,SIGNAL(clicked()),this,SLOT(refreshButtonClicked())); + +} + +ArduRoverPidConfig::~ArduRoverPidConfig() +{ +} +void ArduRoverPidConfig::writeButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=nameToBoxMap.constBegin();i!=nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->setParameter(1,i.key(),i.value()->value()); + } +} + +void ArduRoverPidConfig::refreshButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=nameToBoxMap.constBegin();i!=nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->requestParameterUpdate(1,i.key()); + } +} + +void ArduRoverPidConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (nameToBoxMap.contains(parameterName)) + { + nameToBoxMap[parameterName]->setValue(value.toFloat()); + } +} diff --git a/src/ui/configuration/ArduRoverPidConfig.h b/src/ui/configuration/ArduRoverPidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..214658bdccf2f45dc8e450a2da29e81f60876e49 --- /dev/null +++ b/src/ui/configuration/ArduRoverPidConfig.h @@ -0,0 +1,23 @@ +#ifndef ARDUROVERPIDCONFIG_H +#define ARDUROVERPIDCONFIG_H + +#include +#include "ui_ArduRoverPidConfig.h" +#include "AP2ConfigWidget.h" +class ArduRoverPidConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ArduRoverPidConfig(QWidget *parent = 0); + ~ArduRoverPidConfig(); +private slots: + void writeButtonClicked(); + void refreshButtonClicked(); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap nameToBoxMap; + Ui::ArduRoverPidConfig ui; +}; + +#endif // ARDUROVERPIDCONFIG_H diff --git a/src/ui/configuration/ArduRoverPidConfig.ui b/src/ui/configuration/ArduRoverPidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..47831616e0adbd2578e60934c450c831c1ea7ce3 --- /dev/null +++ b/src/ui/configuration/ArduRoverPidConfig.ui @@ -0,0 +1,732 @@ + + + ArduRoverPidConfig + + + + 0 + 0 + 626 + 607 + + + + Form + + + + + 10 + 10 + 151 + 21 + + + + <h2>ArduRover Pids</h2> + + + + + + 60 + 90 + 504 + 419 + + + + + + + Steer 2 Servo + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Speed 2 Throttle + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Heading 2 Steer + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Throttle 0-100% + + + + + + + + + + Cruise + + + + + + + Min + + + + + + + Max + + + + + + + FS Value + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Xtrack Pids + + + + + + + + + + Gain (cm) + + + + + + + Entry Angle + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Sonar + + + + + + + + + + Trigger cm + + + + + + + Turn Angle + + + + + + + Turn Time + + + + + + + Debounce + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Rover + + + + + + + + + + Cruise Speed + + + + + + + Turn Speed + + + + + + + Turn Dist + + + + + + + WP Radius + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + + + 300 + 540 + 91 + 23 + + + + Refresh Params + + + + + + 200 + 540 + 75 + 23 + + + + Write Params + + + + + + diff --git a/src/ui/configuration/BasicPidConfig.cc b/src/ui/configuration/BasicPidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..938940e5f0912b7363f36f708c0b7a55b3700089 --- /dev/null +++ b/src/ui/configuration/BasicPidConfig.cc @@ -0,0 +1,11 @@ +#include "BasicPidConfig.h" + + +BasicPidConfig::BasicPidConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +BasicPidConfig::~BasicPidConfig() +{ +} diff --git a/src/ui/configuration/BasicPidConfig.h b/src/ui/configuration/BasicPidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..3129239416bbd244b7e5547b5d03c0adb42e3c67 --- /dev/null +++ b/src/ui/configuration/BasicPidConfig.h @@ -0,0 +1,19 @@ +#ifndef BASICPIDCONFIG_H +#define BASICPIDCONFIG_H + +#include +#include "ui_BasicPidConfig.h" + +class BasicPidConfig : public QWidget +{ + Q_OBJECT + +public: + explicit BasicPidConfig(QWidget *parent = 0); + ~BasicPidConfig(); + +private: + Ui::BasicPidConfig ui; +}; + +#endif // BASICPIDCONFIG_H diff --git a/src/ui/configuration/BasicPidConfig.ui b/src/ui/configuration/BasicPidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..4be479c989c42bc7f0b61515609a91d1882f61cf --- /dev/null +++ b/src/ui/configuration/BasicPidConfig.ui @@ -0,0 +1,32 @@ + + + BasicPidConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 30 + 20 + 141 + 31 + + + + <h2> Basic Pids</h2> + + + + + + diff --git a/src/ui/configuration/BatteryMonitorConfig.cc b/src/ui/configuration/BatteryMonitorConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..6e56877884a1f843a5567808fb6f16b9e8edbd0b --- /dev/null +++ b/src/ui/configuration/BatteryMonitorConfig.cc @@ -0,0 +1,311 @@ +#include "BatteryMonitorConfig.h" +#include + +BatteryMonitorConfig::BatteryMonitorConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.monitorComboBox->addItem(tr("0: Disabled")); + ui.monitorComboBox->addItem(tr("3: Battery Volts")); + ui.monitorComboBox->addItem(tr("4: Voltage and Current")); + + ui.sensorComboBox->addItem(tr("0: Other")); + ui.sensorComboBox->addItem("1: AttoPilot 45A"); + ui.sensorComboBox->addItem("2: AttoPilot 90A"); + ui.sensorComboBox->addItem("3: AttoPilot 180A"); + ui.sensorComboBox->addItem("4: 3DR Power Module"); + + ui.apmVerComboBox->addItem("0: APM1"); + ui.apmVerComboBox->addItem("1: APM2 - 2.5 non 3DR"); + ui.apmVerComboBox->addItem("2: APM2.5 - 3DR Power Module"); + ui.apmVerComboBox->addItem("3: PX4"); + + ui.alertOnLowCheckBox->setVisible(false); //Unimpelemented, but TODO. + + + connect(ui.monitorComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(monitorCurrentIndexChanged(int))); + connect(ui.sensorComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sensorCurrentIndexChanged(int))); + connect(ui.apmVerComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(apmVerCurrentIndexChanged(int))); + + connect(ui.calcDividerLineEdit,SIGNAL(editingFinished()),this,SLOT(calcDividerSet())); + connect(ui.ampsPerVoltsLineEdit,SIGNAL(editingFinished()),this,SLOT(ampsPerVoltSet())); + connect(ui.battCapacityLineEdit,SIGNAL(editingFinished()),this,SLOT(batteryCapacitySet())); + + + +} +void BatteryMonitorConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(batteryChanged(UASInterface*,double,double,double,int)),this,SLOT(batteryChanged(UASInterface*,double,double,double,int))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(uas,SIGNAL(batteryChanged(UASInterface*,double,double,double,int)),this,SLOT(batteryChanged(UASInterface*,double,double,double,int))); + +} +void BatteryMonitorConfig::alertOnLowClicked(bool checked) +{ +} + +void BatteryMonitorConfig::calcDividerSet() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + bool ok = false; + float newval = ui.calcDividerLineEdit->text().toFloat(&ok); + if (!ok) + { + //Error parsing; + QMessageBox::information(0,"Error","Invalid number entered for voltage divider. Please try again"); + return; + } + m_uas->getParamManager()->setParameter(1,"VOLT_DIVIDER",newval); +} +void BatteryMonitorConfig::ampsPerVoltSet() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + bool ok = false; + float newval = ui.ampsPerVoltsLineEdit->text().toFloat(&ok); + if (!ok) + { + //Error parsing; + QMessageBox::information(0,"Error","Invalid number entered for amps per volts. Please try again"); + return; + } + m_uas->getParamManager()->setParameter(1,"AMPS_PER_VOLT",newval); +} +void BatteryMonitorConfig::batteryCapacitySet() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + bool ok = false; + float newval = ui.battCapacityLineEdit->text().toFloat(&ok); + if (!ok) + { + //Error parsing; + QMessageBox::information(0,"Error","Invalid number entered for amps per volts. Please try again"); + return; + } + m_uas->getParamManager()->setParameter(1,"BATT_CAPACITY",newval); +} + +void BatteryMonitorConfig::monitorCurrentIndexChanged(int index) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (index == 0) //Battery Monitor Disabled + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",-1); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",-1); + m_uas->getParamManager()->setParameter(1,"BATT_MONITOR",0); + ui.sensorComboBox->setEnabled(false); + ui.apmVerComboBox->setEnabled(false); + ui.measuredVoltsLineEdit->setEnabled(false); + ui.measuredVoltsLineEdit->setEnabled(false); + ui.calcDividerLineEdit->setEnabled(false); + ui.calcVoltsLineEdit->setEnabled(false); + ui.ampsPerVoltsLineEdit->setEnabled(false); + } + else if (index == 1) //Monitor voltage only + { + m_uas->getParamManager()->setParameter(1,"BATT_MONITOR",3); + ui.sensorComboBox->setEnabled(false); + ui.apmVerComboBox->setEnabled(true); + ui.measuredVoltsLineEdit->setEnabled(true); + ui.calcDividerLineEdit->setEnabled(true); + ui.calcVoltsLineEdit->setEnabled(false); + ui.ampsPerVoltsLineEdit->setEnabled(false); + } + else if (index == 2) //Monitor voltage and current + { + m_uas->getParamManager()->setParameter(1,"BATT_MONITOR",4); + ui.sensorComboBox->setEnabled(true); + ui.apmVerComboBox->setEnabled(true); + ui.measuredVoltsLineEdit->setEnabled(true); + ui.calcDividerLineEdit->setEnabled(true); + ui.calcVoltsLineEdit->setEnabled(false); + ui.ampsPerVoltsLineEdit->setEnabled(true); + } + + +} +void BatteryMonitorConfig::sensorCurrentIndexChanged(int index) +{ + float maxvolt = 0.0; + float maxamps = 0.0; + float mvpervolt = 0.0; + float mvperamp = 0.0; + float topvolt = 0.0; + float topamps = 0.0; + + if (index == 1) + { + //atto 45 see https://www.sparkfun.com/products/10643 + maxvolt = 13.6; + maxamps = 44.7; + } + else if (index == 2) + { + //atto 90 see https://www.sparkfun.com/products/9028 + maxvolt = 51.8; + maxamps = 89.4; + } + else if (index == 3) + { + //atto 180 see https://www.sparkfun.com/products/10644 + maxvolt = 51.8; + maxamps = 178.8; + } + else if (index == 4) + { + //3dr + maxvolt = 50.0; + maxamps = 90.0; + } + mvpervolt = calculatemVPerVolt(3.3,maxvolt); + mvperamp = calculatemVPerAmp(3.3,maxamps); + if (index == 0) + { + //Other + ui.ampsPerVoltsLineEdit->setEnabled(true); + ui.calcDividerLineEdit->setEnabled(true); + ui.measuredVoltsLineEdit->setEnabled(true); + } + else + { + topvolt = (maxvolt * mvpervolt) / 1000.0; + topamps = (maxamps * mvperamp) / 1000.0; + + ui.calcDividerLineEdit->setText(QString::number(maxvolt/topvolt)); + ui.ampsPerVoltsLineEdit->setText(QString::number(maxamps / topamps)); + ui.ampsPerVoltsLineEdit->setEnabled(false); + ui.calcDividerLineEdit->setEnabled(false); + ui.measuredVoltsLineEdit->setEnabled(false); + } +} +float BatteryMonitorConfig::calculatemVPerAmp(float maxvoltsout,float maxamps) +{ + return (1000.0 * (maxvoltsout/maxamps)); +} + +float BatteryMonitorConfig::calculatemVPerVolt(float maxvoltsout,float maxvolts) +{ + return (1000.0 * (maxvoltsout/maxvolts)); +} + +void BatteryMonitorConfig::apmVerCurrentIndexChanged(int index) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (index == 0) //APM1 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",0); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",1); + } + else if (index == 1) //APM2 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",1); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",2); + } + else if (index == 2) //APM2.5 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",13); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",12); + } + else if (index == 3) //PX4 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",100); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",101); + m_uas->getParamManager()->setParameter(1,"VOLT_DIVIDER",1); + ui.calcDividerLineEdit->setText("1"); + } +} + +BatteryMonitorConfig::~BatteryMonitorConfig() +{ +} +void BatteryMonitorConfig::batteryChanged(UASInterface* uas, double voltage, double current, double percent, int seconds) +{ + ui.calcVoltsLineEdit->setText(QString::number(voltage,'f',2)); + if (ui.measuredVoltsLineEdit->text() == "") + { + ui.measuredVoltsLineEdit->setText(ui.calcVoltsLineEdit->text()); + } +} + +void BatteryMonitorConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "VOLT_DIVIDER") + { + ui.calcDividerLineEdit->setText(QString::number(value.toFloat(),'f',4)); + } + else if (parameterName == "AMP_PER_VOLT") + { + ui.ampsPerVoltsLineEdit->setText(QString::number(value.toFloat(),'g',2)); + + } + else if (parameterName == "BATT_MONITOR") + { + if (value.toInt() == 0) //0: Disable + { + ui.monitorComboBox->setCurrentIndex(0); + } + else if (value.toInt() == 3) //3: Battery volts + { + ui.monitorComboBox->setCurrentIndex(1); + } + else if (value.toInt() == 4) //4: Voltage and Current + { + ui.monitorComboBox->setCurrentIndex(2); + } + + } + else if (parameterName == "BATT_CAPACITY") + { + ui.battCapacityLineEdit->setText(QString::number(value.toFloat())); + } + else if (parameterName == "BATT_VOLT_PIN") + { + int ivalue = value.toInt(); + if (ivalue == 0) //APM1 + { + ui.apmVerComboBox->setCurrentIndex(0); + } + else if (ivalue == 1) //APM2 + { + ui.apmVerComboBox->setCurrentIndex(1); + } + else if (ivalue == 13) //APM2.5 + { + ui.apmVerComboBox->setCurrentIndex(2); + } + else if (ivalue == 100) //PX4 + { + ui.apmVerComboBox->setCurrentIndex(3); + } + } + else if (parameterName == "BATT_CURR_PIN") + { + //Unused at the moment, everything is off BATT_VOLT_PIN + } +} diff --git a/src/ui/configuration/BatteryMonitorConfig.h b/src/ui/configuration/BatteryMonitorConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..417e6922a95e8fe73e71f1041c0a9865ac3bb182 --- /dev/null +++ b/src/ui/configuration/BatteryMonitorConfig.h @@ -0,0 +1,32 @@ +#ifndef BATTERYMONITORCONFIG_H +#define BATTERYMONITORCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_BatteryMonitorConfig.h" + +class BatteryMonitorConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit BatteryMonitorConfig(QWidget *parent = 0); + ~BatteryMonitorConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void monitorCurrentIndexChanged(int index); + void sensorCurrentIndexChanged(int index); + void apmVerCurrentIndexChanged(int index); + void calcDividerSet(); + void ampsPerVoltSet(); + void batteryCapacitySet(); + void alertOnLowClicked(bool checked); + void activeUASSet(UASInterface *uas); + void batteryChanged(UASInterface* uas, double voltage, double current, double percent, int seconds); +private: + Ui::BatteryMonitorConfig ui; + inline float calculatemVPerAmp(float maxvoltsout,float maxamps); + inline float calculatemVPerVolt(float maxvoltsout,float maxvolts); +}; + +#endif // BATTERYMONITORCONFIG_H diff --git a/src/ui/configuration/BatteryMonitorConfig.ui b/src/ui/configuration/BatteryMonitorConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..5d11f960adc90b000a3ff7e3c50c464a039c6644 --- /dev/null +++ b/src/ui/configuration/BatteryMonitorConfig.ui @@ -0,0 +1,231 @@ + + + BatteryMonitorConfig + + + + 0 + 0 + 745 + 494 + + + + Form + + + + + 20 + 20 + 141 + 31 + + + + <h2>Battery Monitor</h2> + + + false + + + + + + 10 + 70 + 141 + 51 + + + + + + + :/files/images/devices/BR-APMPWRDEAN-2.jpg + + + true + + + + + + 480 + 120 + 91 + 17 + + + + Alert On Low + + + + + + 160 + 170 + 241 + 141 + + + + Calibration + + + + + + + + + + 1. Measured battery voltage: + + + + + + + 2. Battery voltage (Calc'ed): + + + + + + + 3. Voltage divider (Calc'ed): + + + + + + + 4. Amperes per volt: + + + + + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + + + + + + + 160 + 70 + 281 + 91 + + + + + + + + + Monitor + + + + + + + Sensor + + + + + + + APM Version + + + + + + + + + + + + + + + + + + + + + + + + 470 + 70 + 195 + 41 + + + + + + + Battery Capacity: + + + + + + + + + + mAh + + + + + + + + + + + diff --git a/src/ui/configuration/CameraGimbalConfig.cc b/src/ui/configuration/CameraGimbalConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..724dd4bc1d525c5dd9a86c025a2daba57d0f4b58 --- /dev/null +++ b/src/ui/configuration/CameraGimbalConfig.cc @@ -0,0 +1,666 @@ +#include +#include + +#include "CameraGimbalConfig.h" + +CameraGimbalConfig::CameraGimbalConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.tiltChannelComboBox->addItem(tr("Disable")); + ui.tiltChannelComboBox->addItem("RC5"); + ui.tiltChannelComboBox->addItem("RC6"); + ui.tiltChannelComboBox->addItem("RC7"); + ui.tiltChannelComboBox->addItem("RC8"); + ui.tiltChannelComboBox->addItem("RC10"); + ui.tiltChannelComboBox->addItem("RC11"); + + ui.tiltInputChannelComboBox->addItem(tr("Disable")); + ui.tiltInputChannelComboBox->addItem("RC5"); + ui.tiltInputChannelComboBox->addItem("RC6"); + ui.tiltInputChannelComboBox->addItem("RC7"); + ui.tiltInputChannelComboBox->addItem("RC8"); + + ui.rollChannelComboBox->addItem(tr("Disable")); + ui.rollChannelComboBox->addItem("RC5"); + ui.rollChannelComboBox->addItem("RC6"); + ui.rollChannelComboBox->addItem("RC7"); + ui.rollChannelComboBox->addItem("RC8"); + ui.rollChannelComboBox->addItem("RC10"); + ui.rollChannelComboBox->addItem("RC11"); + + ui.rollInputChannelComboBox->addItem(tr("Disable")); + ui.rollInputChannelComboBox->addItem("RC5"); + ui.rollInputChannelComboBox->addItem("RC6"); + ui.rollInputChannelComboBox->addItem("RC7"); + ui.rollInputChannelComboBox->addItem("RC8"); + + + ui.panChannelComboBox->addItem(tr("Disable")); + ui.panChannelComboBox->addItem("RC5"); + ui.panChannelComboBox->addItem("RC6"); + ui.panChannelComboBox->addItem("RC7"); + ui.panChannelComboBox->addItem("RC8"); + ui.panChannelComboBox->addItem("RC10"); + ui.panChannelComboBox->addItem("RC11"); + + ui.panInputChannelComboBox->addItem(tr("Disable")); + ui.panInputChannelComboBox->addItem("RC5"); + ui.panInputChannelComboBox->addItem("RC6"); + ui.panInputChannelComboBox->addItem("RC7"); + ui.panInputChannelComboBox->addItem("RC8"); + + + ui.shutterChannelComboBox->addItem(tr("Disable")); + ui.shutterChannelComboBox->addItem(tr("Relay")); + ui.shutterChannelComboBox->addItem(tr("Transistor")); + ui.shutterChannelComboBox->addItem("RC5"); + ui.shutterChannelComboBox->addItem("RC6"); + ui.shutterChannelComboBox->addItem("RC7"); + ui.shutterChannelComboBox->addItem("RC8"); + ui.shutterChannelComboBox->addItem("RC10"); + ui.shutterChannelComboBox->addItem("RC11"); + + connect(ui.tiltServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltAngleMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltAngleMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + connect(ui.tiltInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + connect(ui.tiltReverseCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateTilt())); + connect(ui.tiltStabilizeCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateTilt())); + + connect(ui.rollServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollAngleMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollAngleMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + connect(ui.rollInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + connect(ui.rollReverseCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateRoll())); + connect(ui.rollStabilizeCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateRoll())); + + connect(ui.panServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panAngleMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panAngleMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + connect(ui.panInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + connect(ui.panReverseCheckBox,SIGNAL(clicked(bool)),this,SLOT(updatePan())); + connect(ui.panStabilizeCheckBox,SIGNAL(clicked(bool)),this,SLOT(updatePan())); + + + connect(ui.shutterServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterPushedSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterNotPushedSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterDurationSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + + connect(ui.retractXSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRetractAngles())); + connect(ui.retractYSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRetractAngles())); + connect(ui.retractZSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRetractAngles())); + + connect(ui.controlXSpinBox,SIGNAL(editingFinished()),this,SLOT(updateControlAngles())); + connect(ui.controlYSpinBox,SIGNAL(editingFinished()),this,SLOT(updateControlAngles())); + connect(ui.controlZSpinBox,SIGNAL(editingFinished()),this,SLOT(updateControlAngles())); + + connect(ui.neutralXSpinBox,SIGNAL(editingFinished()),this,SLOT(updateNeutralAngles())); + connect(ui.neutralYSpinBox,SIGNAL(editingFinished()),this,SLOT(updateNeutralAngles())); + connect(ui.neutralZSpinBox,SIGNAL(editingFinished()),this,SLOT(updateNeutralAngles())); + + +} +void CameraGimbalConfig::updateRetractAngles() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"MNT_RETRACT_X",ui.retractXSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_RETRACT_Y",ui.retractYSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_RETRACT_Z",ui.retractZSpinBox->value()); +} + +void CameraGimbalConfig::updateNeutralAngles() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"MNT_NEUTRAL_X",ui.neutralXSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_NEUTRAL_Y",ui.neutralYSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_NEUTRAL_Z",ui.neutralZSpinBox->value()); +} + +void CameraGimbalConfig::updateControlAngles() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"MNT_CONTROL_X",ui.controlXSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_CONTROL_Y",ui.controlYSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_CONTROL_Z",ui.controlZSpinBox->value()); +} + +void CameraGimbalConfig::updateTilt() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (!m_tiltPrefix.isEmpty()) + { + //We need to set this to 0 for disabled. + m_uas->getParamManager()->setParameter(1,m_tiltPrefix + "FUNCTION",0); + } + if (ui.tiltChannelComboBox->currentIndex() == 0) + { + //Disabled + return; + } + + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_FUNCTION",7); + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_MIN",ui.tiltServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_MAX",ui.tiltServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMIN_TIL",ui.tiltAngleMinSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMAX_TIL",ui.tiltAngleMaxSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_REV",(ui.tiltReverseCheckBox->isChecked() ? 1 : 0)); + if (ui.tiltInputChannelComboBox->currentIndex() == 0) + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_TILT",0); + } + else + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_TILT",ui.tiltInputChannelComboBox->currentIndex()+4); + } +} + +void CameraGimbalConfig::updateRoll() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_FUNCTION",8); + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_MIN",ui.rollServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_MAX",ui.rollServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMIN_ROL",ui.rollAngleMinSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMAX_ROL",ui.rollAngleMaxSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_REV",(ui.rollReverseCheckBox->isChecked() ? 1 : 0)); + if (ui.rollInputChannelComboBox->currentIndex() == 0) + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_ROLL",0); + } + else + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_ROLL",ui.rollInputChannelComboBox->currentIndex()+4); + } +} + +void CameraGimbalConfig::updatePan() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_FUNCTION",6); + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_MIN",ui.panServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_MAX",ui.panServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMIN_PAN",ui.panAngleMinSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMAX_PAN",ui.panAngleMaxSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_REV",(ui.panReverseCheckBox->isChecked() ? 1 : 0)); + if (ui.panInputChannelComboBox->currentIndex() == 0) + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_PAN",0); + } + else + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_PAN",ui.panInputChannelComboBox->currentIndex()+4); + } +} + +void CameraGimbalConfig::updateShutter() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (ui.shutterChannelComboBox->currentIndex() == 0) //Disabled + { + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",0); + } + else if (ui.shutterChannelComboBox->currentIndex() == 1) //Relay + { + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",1); + } + else if (ui.shutterChannelComboBox->currentIndex() == 2) //Transistor + { + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",4); + } + else + { + m_uas->getParamManager()->setParameter(1,ui.shutterChannelComboBox->currentText() + "_FUNCTION",10); + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",0); + } + m_uas->getParamManager()->setParameter(1,ui.shutterChannelComboBox->currentText() + "_MIN",ui.shutterServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.shutterChannelComboBox->currentText() + "_MAX",ui.shutterServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"CAM_SERVO_ON",ui.shutterPushedSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"CAM_SERVO_OFF",ui.shutterNotPushedSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"CAM_DURATION",ui.shutterDurationSpinBox->value()); + + +} + + +CameraGimbalConfig::~CameraGimbalConfig() +{ +} + +void CameraGimbalConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "MNT_ANGMIN_TIL") //TILT + { + ui.tiltAngleMinSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_ANGMAX_TIL") + { + ui.tiltAngleMaxSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_RC_IN_TILT") + { + disconnect(ui.tiltInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + if (value.toInt() == 0) + { + ui.tiltInputChannelComboBox->setCurrentIndex(0); + } + else + { + ui.tiltInputChannelComboBox->setCurrentIndex(value.toInt()-4); + } + connect(ui.tiltInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + } + else if (parameterName == "MNT_ANGMIN_ROL") //ROLL + { + ui.rollAngleMinSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_ANGMAX_ROL") + { + ui.rollAngleMaxSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_RC_IN_ROLL") + { + disconnect(ui.rollInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + if (value.toInt() == 0) + { + ui.rollInputChannelComboBox->setCurrentIndex(0); + } + else + { + ui.rollInputChannelComboBox->setCurrentIndex(value.toInt()-4); + } + connect(ui.rollInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + } + else if (parameterName == "MNT_ANGMIN_PAN") //PAN + { + ui.panAngleMinSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_ANGMAX_PAN") + { + ui.panAngleMaxSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_RC_IN_PAN") + { + disconnect(ui.panInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + if (value.toInt() == 0) + { + ui.panInputChannelComboBox->setCurrentIndex(0); + } + else + { + ui.panInputChannelComboBox->setCurrentIndex(value.toInt()-4); + } + connect(ui.panInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + } + if (parameterName == "CAM_DURATION") + { + ui.shutterDurationSpinBox->setValue(value.toInt()); + } + else if (parameterName == "CAM_SERVO_OFF") + { + ui.shutterNotPushedSpinBox->setValue(value.toInt()); + } + else if (parameterName == "CAM_SERVO_ON") + { + ui.shutterPushedSpinBox->setValue(value.toInt()); + } + else if (parameterName == "CAM_TRIGG_TYPE") + { + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + if (value.toInt() == 0) //Disabled + { + ui.shutterChannelComboBox->setCurrentIndex(0); + ///TODO: Request all _FUNCTIONs here to find out if shutter is actually disabled. + } + else if (value.toInt() == 1) // Relay + { + ui.shutterChannelComboBox->setCurrentIndex(1); + } + else if (value.toInt() == 4) //Transistor + { + ui.shutterChannelComboBox->setCurrentIndex(2); + } + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + } + if (parameterName.startsWith(m_shutterPrefix) && !m_shutterPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.shutterServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.shutterServoMaxSpinBox->setValue(value.toInt()); + } + } + else if (parameterName.startsWith(m_tiltPrefix) && !m_tiltPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.tiltServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.tiltServoMaxSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("REV")) + { + if (value.toInt() == 0) + { + ui.tiltReverseCheckBox->setChecked(false); + } + else + { + ui.tiltReverseCheckBox->setChecked(true); + } + } + } + else if (parameterName.startsWith(m_rollPrefix) && !m_rollPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.rollServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.rollServoMaxSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("REV")) + { + if (value.toInt() == 0) + { + ui.rollReverseCheckBox->setChecked(false); + } + else + { + ui.rollReverseCheckBox->setChecked(true); + } + } + } + else if (parameterName.startsWith(m_panPrefix) && !m_panPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.panServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.panServoMaxSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("REV")) + { + if (value.toInt() == 0) + { + ui.panReverseCheckBox->setChecked(false); + } + else + { + ui.panReverseCheckBox->setChecked(true); + } + } + } + else if (parameterName == "RC5_FUNCTION") + { + if (value.toInt() == 10) + { + //RC5 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(3); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC5_"; + } + else if (value.toInt() == 8) + { + //RC5 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(1); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC5_"; + } + else if (value.toInt() == 7) + { + //RC5 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(1); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC5_"; + } + else if (value.toInt() == 6) + { + //RC5 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(1); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC5_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC5_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC5_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC5_REV"); + } + else if (parameterName == "RC6_FUNCTION") + { + if (value.toInt() == 10) + { + //RC6 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(4); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC6_"; + } + else if (value.toInt() == 8) + { + //RC6 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(2); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC6_"; + } + else if (value.toInt() == 7) + { + //RC6 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(2); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC6_"; + } + else if (value.toInt() == 6) + { + //RC6 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(2); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC6_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC6_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC6_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC6_REV"); + } + else if (parameterName == "RC7_FUNCTION") + { + if (value.toInt() == 10) + { + //RC7 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(5); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC7_"; + } + else if (value.toInt() == 8) + { + //RC7 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(3); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC7_"; + } + else if (value.toInt() == 7) + { + //RC7 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(3); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC7_"; + } + else if (value.toInt() == 6) + { + //RC7 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(3); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC7_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC7_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC7_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC7_REV"); + } + else if (parameterName == "RC8_FUNCTION") + { + if (value.toInt() == 10) + { + //RC8 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(6); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC8_"; + } + else if (value.toInt() == 8) + { + //RC8 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(4); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC8_"; + } + else if (value.toInt() == 7) + { + //RC8 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(4); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC8_"; + } + else if (value.toInt() == 6) + { + //RC8 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(4); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC8_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC8_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC8_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC8_REV"); + } + else if (parameterName == "RC10_FUNCTION") + { + if (value.toInt() == 10) + { + //RC10 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(7); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC10_"; + } + else if (value.toInt() == 8) + { + //RC10 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(5); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC10_"; + } + else if (value.toInt() == 7) + { + //RC10 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(5); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC10_"; + } + else if (value.toInt() == 6) + { + //RC10 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(5); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC10_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC10_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC10_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC10_REV"); + } + else if (parameterName == "RC11_FUNCTION") + { + if (value.toInt() == 10) + { + //RC11 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(8); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC11_"; + } + else if (value.toInt() == 8) + { + //RC11 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(6); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC11_"; + } + else if (value.toInt() == 7) + { + //RC11 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(6); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC11_"; + } + else if (value.toInt() == 6) + { + //RC11 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(6); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC11_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC11_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC11_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC11_REV"); + } +} diff --git a/src/ui/configuration/CameraGimbalConfig.h b/src/ui/configuration/CameraGimbalConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..9f686243f707e689ee25dcfa390598cd81527d94 --- /dev/null +++ b/src/ui/configuration/CameraGimbalConfig.h @@ -0,0 +1,32 @@ +#ifndef CAMERAGIMBALCONFIG_H +#define CAMERAGIMBALCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_CameraGimbalConfig.h" + +class CameraGimbalConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit CameraGimbalConfig(QWidget *parent = 0); + ~CameraGimbalConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void updateTilt(); + void updateRoll(); + void updatePan(); + void updateShutter(); + void updateRetractAngles(); + void updateNeutralAngles(); + void updateControlAngles(); +private: + Ui::CameraGimbalConfig ui; + QString m_shutterPrefix; + QString m_rollPrefix; + QString m_tiltPrefix; + QString m_panPrefix; +}; + +#endif // CAMERAGIMBALCONFIG_H diff --git a/src/ui/configuration/CameraGimbalConfig.ui b/src/ui/configuration/CameraGimbalConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..1775b5945e38bc7c009e59443088c3b129ba6592 --- /dev/null +++ b/src/ui/configuration/CameraGimbalConfig.ui @@ -0,0 +1,965 @@ + + + CameraGimbalConfig + + + + 0 + 0 + 959 + 813 + + + + Form + + + + + 30 + 20 + 131 + 31 + + + + <h2>Camera Gimbal</h2> + + + false + + + + + + 30 + 60 + 541 + 151 + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <h3>Input Ch</h3> + + + + + + + Reverse + + + + + + + <h3>Angle Limits</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Tilt</h2> + + + Qt::AlignCenter + + + + + + + Stabilize Tilt + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/cameraGimalPitch1.png + + + true + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + 100 + + + 0 + + + + + + + + + + + + 30 + 230 + 541 + 149 + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h3>Input Ch</h3> + + + + + + + Reverse + + + + + + + <h3>Angle Limits</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Roll</h2> + + + Qt::AlignCenter + + + + + + + Stabilize Roll + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/cameraGimalRoll1.png + + + true + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + + + 30 + 390 + 541 + 149 + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h3>Input Ch</h3> + + + + + + + Reverse + + + + + + + <h3>Angle Limits</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Pan</h2> + + + Qt::AlignCenter + + + + + + + Stabilize Pan + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/cameraGimalYaw.png + + + true + + + + + + + 3000 + + + 1000 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + 3000 + + + 2000 + + + + + + + + + 30 + 550 + 541 + 181 + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/Shutter.png + + + true + + + + + + + Duration +(1/10th sec) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Pushed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Not Pushed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <h3>Shutter</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Shutter</h2> + + + Qt::AlignCenter + + + + + + + <h2>Please set the Ch7 Option to Camera Trigger</h2> + + + Qt::AlignCenter + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + 100 + + + 20 + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + + + 590 + 60 + 171 + 131 + + + + Retract Angles + + + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + + + + + + + 590 + 210 + 171 + 131 + + + + Neutral Angles + + + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + + + + + + + 590 + 360 + 171 + 131 + + + + Control Angles + + + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/CompassConfig.cc b/src/ui/configuration/CompassConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..d0cbcc7ada79b089fb767eee33dd99362bb43f61 --- /dev/null +++ b/src/ui/configuration/CompassConfig.cc @@ -0,0 +1,135 @@ +#include "CompassConfig.h" + + +CompassConfig::CompassConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.autoDecCheckBox->setEnabled(false); + ui.enableCheckBox->setEnabled(false); + ui.orientationComboBox->setEnabled(false); + ui.declinationLineEdit->setEnabled(false); + connect(ui.enableCheckBox,SIGNAL(clicked(bool)),this,SLOT(enableClicked(bool))); + connect(ui.autoDecCheckBox,SIGNAL(clicked(bool)),this,SLOT(autoDecClicked(bool))); + connect(ui.orientationComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(orientationComboChanged(int))); + + ui.orientationComboBox->addItem("ROTATION_NONE"); + ui.orientationComboBox->addItem("ROTATION_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_YAW_180"); + ui.orientationComboBox->addItem("ROTATION_YAW_225"); + ui.orientationComboBox->addItem("ROTATION_YAW_270"); + ui.orientationComboBox->addItem("ROTATION_YAW_315"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_PITCH_180"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_225"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_270"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_315"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_PITCH_90"); + ui.orientationComboBox->addItem("ROTATION_PITCH_270"); + ui.orientationComboBox->addItem("ROTATION_MAX"); +} +CompassConfig::~CompassConfig() +{ +} +void CompassConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "MAG_ENABLE") + { + if (value.toInt() == 0) + { + ui.enableCheckBox->setChecked(false); + ui.autoDecCheckBox->setEnabled(false); + ui.declinationLineEdit->setEnabled(false); + ui.orientationComboBox->setEnabled(false); + } + else + { + ui.enableCheckBox->setChecked(true); + ui.autoDecCheckBox->setEnabled(true); + ui.declinationLineEdit->setEnabled(true); + ui.orientationComboBox->setEnabled(true); + } + ui.enableCheckBox->setEnabled(true); + } + else if (parameterName == "COMPASS_AUTODEC") + { + if (value.toInt() == 0) + { + ui.autoDecCheckBox->setChecked(false); + } + else + { + ui.autoDecCheckBox->setChecked(true); + } + } + else if (parameterName == "COMPASS_DEC") + { + ui.declinationLineEdit->setText(QString::number(value.toDouble())); + } + else if (parameterName == "COMPASS_ORIENT") + { + disconnect(ui.orientationComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(orientationComboChanged(int))); + ui.orientationComboBox->setCurrentIndex(value.toInt()); + connect(ui.orientationComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(orientationComboChanged(int))); + } +} + +void CompassConfig::enableClicked(bool enabled) +{ + if (m_uas) + { + if (enabled) + { + m_uas->getParamManager()->setParameter(1,"MAG_ENABLE",QVariant(1)); + ui.autoDecCheckBox->setEnabled(true); + if (!ui.autoDecCheckBox->isChecked()) + { + ui.declinationLineEdit->setEnabled(true); + } + } + else + { + m_uas->getParamManager()->setParameter(1,"MAG_ENABLE",QVariant(0)); + ui.autoDecCheckBox->setEnabled(false); + ui.declinationLineEdit->setEnabled(false); + } + } +} + +void CompassConfig::autoDecClicked(bool enabled) +{ + if (m_uas) + { + if (enabled) + { + m_uas->getParamManager()->setParameter(1,"COMPASS_AUTODEC",QVariant(1)); + } + else + { + m_uas->getParamManager()->setParameter(1,"COMPASS_AUTODEC",QVariant(0)); + } + } +} + +void CompassConfig::orientationComboChanged(int index) +{ + //COMPASS_ORIENT + if (!m_uas) + { + return; + } + m_uas->getParamManager()->setParameter(1,"COMPASS_ORIENT",index); + +} diff --git a/src/ui/configuration/CompassConfig.h b/src/ui/configuration/CompassConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..d650c1bebb89fc587934a9d3fbc70377020d2723 --- /dev/null +++ b/src/ui/configuration/CompassConfig.h @@ -0,0 +1,25 @@ +#ifndef COMPASSCONFIG_H +#define COMPASSCONFIG_H + +#include +#include "ui_CompassConfig.h" +#include "UASManager.h" +#include "UASInterface.h" +#include "AP2ConfigWidget.h" +class CompassConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit CompassConfig(QWidget *parent = 0); + ~CompassConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void enableClicked(bool enabled); + void autoDecClicked(bool enabled); + void orientationComboChanged(int index); +private: + Ui::CompassConfig ui; +}; + +#endif // COMPASSCONFIG_H diff --git a/src/ui/configuration/CompassConfig.ui b/src/ui/configuration/CompassConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..95b9362b441dc7279f45a2c26adf80606b89d7ea --- /dev/null +++ b/src/ui/configuration/CompassConfig.ui @@ -0,0 +1,196 @@ + + + CompassConfig + + + + 0 + 0 + 565 + 241 + + + + Form + + + + + 10 + 0 + 521 + 31 + + + + <h2>Compass</h2> + + + false + + + + + + 230 + 100 + 101 + 16 + + + + <a href="http://magnetic-declination.com/">Declination Website</a> + + + + + + 280 + 120 + 201 + 22 + + + + + + + 290 + 180 + 101 + 23 + + + + Live Calibration + + + + + + 390 + 180 + 101 + 23 + + + + Log Calibration + + + + + + 340 + 160 + 91 + 16 + + + + Advanced Config + + + + + + 220 + 70 + 321 + 31 + + + + + + + + + + in Degrees eg 2* 3' W is -2.3 + + + + + + + + + 10 + 70 + 211 + 111 + + + + + + + + 100 + 100 + + + + + + + :/files/images/devices/BR-HMC5883-01-2.jpg + + + true + + + + + + + + + Enable + + + + + + + Auto Declination + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 220 + 120 + 54 + 20 + + + + Orientation + + + + + + + + diff --git a/src/ui/configuration/FailSafeConfig.cc b/src/ui/configuration/FailSafeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..0e0d45e3ddf28855d9d3c9a7f1764211d9afa458 --- /dev/null +++ b/src/ui/configuration/FailSafeConfig.cc @@ -0,0 +1,418 @@ +#include "FailSafeConfig.h" + + +FailSafeConfig::FailSafeConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.radio1In->setName("Radio 1"); + ui.radio1In->setMin(800); + ui.radio1In->setMax(2200); + ui.radio1In->setOrientation(Qt::Horizontal); + ui.radio2In->setName("Radio 2"); + ui.radio2In->setMin(800); + ui.radio2In->setMax(2200); + ui.radio2In->setOrientation(Qt::Horizontal); + ui.radio3In->setName("Radio 3"); + ui.radio3In->setMin(800); + ui.radio3In->setMax(2200); + ui.radio3In->setOrientation(Qt::Horizontal); + ui.radio4In->setName("Radio 4"); + ui.radio4In->setMin(800); + ui.radio4In->setMax(2200); + ui.radio4In->setOrientation(Qt::Horizontal); + ui.radio5In->setName("Radio 5"); + ui.radio5In->setMin(800); + ui.radio5In->setMax(2200); + ui.radio5In->setOrientation(Qt::Horizontal); + ui.radio6In->setName("Radio 6"); + ui.radio6In->setMin(800); + ui.radio6In->setMax(2200); + ui.radio6In->setOrientation(Qt::Horizontal); + ui.radio7In->setName("Radio 7"); + ui.radio7In->setMin(800); + ui.radio7In->setMax(2200); + ui.radio7In->setOrientation(Qt::Horizontal); + ui.radio8In->setName("Radio 8"); + ui.radio8In->setMin(800); + ui.radio8In->setMax(2200); + ui.radio8In->setOrientation(Qt::Horizontal); + + ui.radio1Out->setName("Radio 1"); + ui.radio1Out->setMin(800); + ui.radio1Out->setMax(2200); + ui.radio1Out->setOrientation(Qt::Horizontal); + ui.radio2Out->setName("Radio 2"); + ui.radio2Out->setMin(800); + ui.radio2Out->setMax(2200); + ui.radio2Out->setOrientation(Qt::Horizontal); + ui.radio3Out->setName("Radio 3"); + ui.radio3Out->setMin(800); + ui.radio3Out->setMax(2200); + ui.radio3Out->setOrientation(Qt::Horizontal); + ui.radio4Out->setName("Radio 4"); + ui.radio4Out->setMin(800); + ui.radio4Out->setMax(2200); + ui.radio4Out->setOrientation(Qt::Horizontal); + ui.radio5Out->setName("Radio 5"); + ui.radio5Out->setMin(800); + ui.radio5Out->setMax(2200); + ui.radio5Out->setOrientation(Qt::Horizontal); + ui.radio6Out->setName("Radio 6"); + ui.radio6Out->setMin(800); + ui.radio6Out->setMax(2200); + ui.radio6Out->setOrientation(Qt::Horizontal); + ui.radio7Out->setName("Radio 7"); + ui.radio7Out->setMin(800); + ui.radio7Out->setMax(2200); + ui.radio7Out->setOrientation(Qt::Horizontal); + ui.radio8Out->setName("Radio 8"); + ui.radio8Out->setMin(800); + ui.radio8Out->setMax(2200); + ui.radio8Out->setOrientation(Qt::Horizontal); + + ui.throttleFailSafeComboBox->addItem("Disable"); + ui.throttleFailSafeComboBox->addItem("Enabled - Always TRL"); + ui.throttleFailSafeComboBox->addItem("Enabled - Continue in auto"); + + connect(ui.batteryFailCheckBox,SIGNAL(clicked(bool)),this,SLOT(batteryFailChecked(bool))); + connect(ui.fsLongCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsLongClicked(bool))); + connect(ui.fsShortCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsShortClicked(bool))); + connect(ui.gcsCheckBox,SIGNAL(clicked(bool)),this,SLOT(gcsChecked(bool))); + connect(ui.throttleActionCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleActionChecked(bool))); + connect(ui.throttleCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleChecked(bool))); + connect(ui.throttlePwmSpinBox,SIGNAL(editingFinished()),this,SLOT(throttlePwmChanged())); + connect(ui.throttleFailSafeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(throttleFailSafeChanged(int))); +} +void FailSafeConfig::gcsChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_GCS_ENABL",1); + } + else + { + m_uas->setParameter(1,"FS_GCS_ENABL",0); + } +} + +void FailSafeConfig::throttleActionChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"THR_FS_ACTION",1); + } + else + { + m_uas->setParameter(1,"THR_FS_ACTION",0); + } +} + +void FailSafeConfig::throttleChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"THR_FAILSAFE",1); + } + else + { + m_uas->setParameter(1,"THR_FAILSAFE",0); + } +} + +void FailSafeConfig::throttlePwmChanged() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->setParameter(1,"THR_FS_VALUE",ui.throttlePwmSpinBox->value()); +} + +void FailSafeConfig::throttleFailSafeChanged(int index) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->setParameter(1,"FS_THR_ENABLE",index); +} + +void FailSafeConfig::fsLongClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_LONG_ACTN",1); + } + else + { + m_uas->setParameter(1,"FS_LONG_ACTN",0); + } +} + +void FailSafeConfig::fsShortClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_SHORT_ACTN",1); + } + else + { + m_uas->setParameter(1,"FS_SHORT_ACTN",0); + } +} + +void FailSafeConfig::batteryFailChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_BATT_ENABLE",1); + } + else + { + m_uas->setParameter(1,"FS_BATT_ENABLE",0); + } +} + +FailSafeConfig::~FailSafeConfig() +{ +} +void FailSafeConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float))); + disconnect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float))); + disconnect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float))); + connect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float))); + connect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool))); + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + ui.batteryFailCheckBox->setVisible(false); + ui.throttleFailSafeComboBox->setVisible(false); + ui.batteryVoltSpinBox->setVisible(false); + ui.label_6->setVisible(false); + + ui.throttlePwmSpinBox->setVisible(true); //Both + + ui.throttleCheckBox->setVisible(true); + ui.throttleActionCheckBox->setVisible(true); + ui.gcsCheckBox->setVisible(true); + ui.fsLongCheckBox->setVisible(true); + ui.fsShortCheckBox->setVisible(true); + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + ui.batteryFailCheckBox->setVisible(true); + ui.throttleFailSafeComboBox->setVisible(true); + ui.batteryVoltSpinBox->setVisible(true); + ui.label_6->setVisible(true); + + ui.throttlePwmSpinBox->setVisible(true); //Both + + ui.throttleCheckBox->setVisible(false); + ui.throttleActionCheckBox->setVisible(false); + ui.gcsCheckBox->setVisible(false); + ui.fsLongCheckBox->setVisible(false); + ui.fsShortCheckBox->setVisible(false); + } + else + { + //Show all, just in case + ui.batteryFailCheckBox->setVisible(true); + ui.throttleFailSafeComboBox->setVisible(true); + ui.batteryVoltSpinBox->setVisible(true); + ui.throttlePwmSpinBox->setVisible(true); //Both + ui.throttleCheckBox->setVisible(true); + ui.throttleActionCheckBox->setVisible(true); + ui.gcsCheckBox->setVisible(true); + ui.fsLongCheckBox->setVisible(true); + ui.fsShortCheckBox->setVisible(true); + } + +} +void FailSafeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + //Arducopter + if (parameterName == "FS_THR_ENABLE") + { + ui.throttleFailSafeComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FS_THR_VALUE") + { + ui.throttlePwmSpinBox->setValue(value.toFloat()); + } + else if (parameterName == "FS_BATT_ENABLE") + { + if (value.toInt() == 0) + { + ui.batteryFailCheckBox->setChecked(false); + } + else + { + ui.batteryFailCheckBox->setChecked(true); + } + } + else if (parameterName == "LOW_VOLT") + { + ui.batteryVoltSpinBox->setValue(value.toFloat()); + } + //Arduplane + else if (parameterName == "THR_FAILSAFE") + { + if (value.toInt() == 0) + { + ui.throttleCheckBox->setChecked(false); + } + else + { + ui.throttleCheckBox->setChecked(true); + } + } + else if (parameterName == "THR_FS_VALUE") + { + ui.throttlePwmSpinBox->setValue(value.toFloat()); + } + else if (parameterName == "THR_FS_ACTION") + { + if (value.toInt() == 0) + { + ui.throttleActionCheckBox->setChecked(false); + } + else + { + ui.throttleActionCheckBox->setChecked(true); + } + } + else if (parameterName == "FS_GCS_ENABL") + { + if (value.toInt() == 0) + { + ui.gcsCheckBox->setChecked(false); + } + else + { + ui.gcsCheckBox->setChecked(true); + } + } + else if (parameterName == "FS_SHORT_ACTN") + { + if (value.toInt() == 0) + { + ui.fsShortCheckBox->setChecked(false); + } + else + { + ui.fsShortCheckBox->setChecked(true); + } + } + else if (parameterName == "FS_LONG_ACTN") + { + if (value.toInt() == 0) + { + ui.fsLongCheckBox->setChecked(false); + } + else + { + ui.fsLongCheckBox->setChecked(true); + } + } + +} + +void FailSafeConfig::armingChanged(bool armed) +{ + if (armed) + { + ui.armedLabel->setText("

ARMED

"); + } + else + { + ui.armedLabel->setText("

DISARMED

"); + } +} + +void FailSafeConfig::remoteControlChannelRawChanges(int chan,float value) +{ + if (chan == 0) + { + ui.radio1In->setValue(value); + } + else if (chan == 1) + { + ui.radio2In->setValue(value); + } + else if (chan == 2) + { + ui.radio3In->setValue(value); + } + else if (chan == 3) + { + ui.radio4In->setValue(value); + } + else if (chan == 4) + { + ui.radio5In->setValue(value); + } + else if (chan == 5) + { + ui.radio6In->setValue(value); + } + else if (chan == 6) + { + ui.radio7In->setValue(value); + } + else if (chan == 7) + { + ui.radio8In->setValue(value); + } +} +void FailSafeConfig::hilActuatorsChanged(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8) +{ + ui.radio1Out->setValue(act1); + ui.radio2Out->setValue(act2); + ui.radio3Out->setValue(act3); + ui.radio4Out->setValue(act4); + ui.radio5Out->setValue(act5); + ui.radio6Out->setValue(act6); + ui.radio7Out->setValue(act7); + ui.radio8Out->setValue(act8); +} diff --git a/src/ui/configuration/FailSafeConfig.h b/src/ui/configuration/FailSafeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..162246e899861f560891d8336eaddc631039ea79 --- /dev/null +++ b/src/ui/configuration/FailSafeConfig.h @@ -0,0 +1,32 @@ +#ifndef FAILSAFECONFIG_H +#define FAILSAFECONFIG_H + +#include +#include "ui_FailSafeConfig.h" +#include "AP2ConfigWidget.h" +class FailSafeConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit FailSafeConfig(QWidget *parent = 0); + ~FailSafeConfig(); +private slots: + void activeUASSet(UASInterface *uas); + void remoteControlChannelRawChanges(int chan,float value); + void hilActuatorsChanged(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8); + void armingChanged(bool armed); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void batteryFailChecked(bool checked); + void fsLongClicked(bool checked); + void fsShortClicked(bool checked); + void gcsChecked(bool checked); + void throttleActionChecked(bool checked); + void throttleChecked(bool checked); + void throttlePwmChanged(); + void throttleFailSafeChanged(int index); +private: + Ui::FailSafeConfig ui; +}; + +#endif // FAILSAFECONFIG_H diff --git a/src/ui/configuration/FailSafeConfig.ui b/src/ui/configuration/FailSafeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..69375dd53599967a7c06b48b2aeb1f2f3213397c --- /dev/null +++ b/src/ui/configuration/FailSafeConfig.ui @@ -0,0 +1,452 @@ + + + FailSafeConfig + + + + 0 + 0 + 822 + 536 + + + + Form + + + + + 20 + 20 + 141 + 31 + + + + <h2>Fail Safe</h2> + + + + + + 20 + 70 + 252 + 441 + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + 300 + 70 + 252 + 441 + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + 570 + 60 + 181 + 181 + + + + Status + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + 570 + 250 + 161 + 261 + + + + Failsafe Options + + + + + + Throttle FailSafe + + + + + + + + + + + + FS Pwm + + + + + + + 3000 + + + + + + + + + Throttle FailSafe Action + + + + + + + GCS FailSafe + + + + + + + FailSafe Short (1 sec) + + + + + + + FailSafe Long (20 sec) + + + + + + + Battery Failsafe + + + + + + + + + Low Battery + + + + + + + 100.000000000000000 + + + + + + + + + + + QGCRadioChannelDisplay + QWidget +
ui/designer/QGCRadioChannelDisplay.h
+ 1 +
+
+ + +
diff --git a/src/ui/configuration/FlightModeConfig.cc b/src/ui/configuration/FlightModeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..d5acd58176b2116ba44e8ce99515f6409bb9ee8e --- /dev/null +++ b/src/ui/configuration/FlightModeConfig.cc @@ -0,0 +1,306 @@ +#include "FlightModeConfig.h" + + +FlightModeConfig::FlightModeConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.savePushButton,SIGNAL(clicked()),this,SLOT(saveButtonClicked())); +} + +FlightModeConfig::~FlightModeConfig() +{ +} +void FlightModeConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(modeChanged(int,QString,QString)),this,SLOT(modeChanged(int,QString,QString))); + disconnect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanged(int,float))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) return; + connect(m_uas,SIGNAL(modeChanged(int,QString,QString)),this,SLOT(modeChanged(int,QString,QString))); + connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanged(int,float))); + QStringList itemlist; + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + itemlist << "Manual"; + itemlist << "Circle"; + itemlist << "Stabilize"; + itemlist << "Training"; + itemlist << "FBW A"; + itemlist << "FBW B"; + itemlist << "Auto"; + itemlist << "RTL"; + itemlist << "Loiter"; + itemlist << "Guided"; + + planeModeIndexToUiIndex[0] = 0; + planeModeUiIndexToIndex[0] = 0; + + planeModeIndexToUiIndex[1] = 1; + planeModeUiIndexToIndex[1] = 1; + + planeModeIndexToUiIndex[2] = 2; + planeModeUiIndexToIndex[2] = 2; + + planeModeIndexToUiIndex[3] = 3; + planeModeUiIndexToIndex[3] = 3; + + planeModeIndexToUiIndex[5] = 4; + planeModeUiIndexToIndex[4] = 5; + + planeModeIndexToUiIndex[6] = 5; + planeModeUiIndexToIndex[5] = 6; + + planeModeIndexToUiIndex[10] = 6; + planeModeUiIndexToIndex[6] = 10; + + planeModeIndexToUiIndex[11] = 7; + planeModeUiIndexToIndex[7] = 11; + + planeModeIndexToUiIndex[12] = 8; + planeModeUiIndexToIndex[8] = 12; + + planeModeIndexToUiIndex[15] = 9; + planeModeUiIndexToIndex[9] = 15; + + ui.mode6ComboBox->setEnabled(true); + } + else if (m_uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + itemlist << "Manual"; + itemlist << "Learning"; + itemlist << "Steering"; + itemlist << "Hold"; + itemlist << "Auto"; + itemlist << "RTL"; + itemlist << "Guided"; + itemlist << "Initialising"; + ui.mode6ComboBox->setEnabled(false); + roverModeIndexToUiIndex[0] = 0; + roverModeUiIndexToIndex[0] = 0; + + roverModeIndexToUiIndex[2] = 1; + roverModeUiIndexToIndex[1] = 2; + + roverModeIndexToUiIndex[3] = 2; + roverModeUiIndexToIndex[2] = 3; + + roverModeIndexToUiIndex[4] = 3; + roverModeUiIndexToIndex[3] = 4; + + roverModeIndexToUiIndex[10] = 5; + roverModeUiIndexToIndex[5] = 10; + + roverModeIndexToUiIndex[11] = 6; + roverModeUiIndexToIndex[6] = 11; + + roverModeIndexToUiIndex[15] = 7; + roverModeUiIndexToIndex[7] = 15; + + roverModeIndexToUiIndex[16] = 8; + roverModeUiIndexToIndex[8] = 16; + + + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + itemlist << "Stabilize"; + itemlist << "Acro"; + itemlist << "Alt Hold"; + itemlist << "Auto"; + itemlist << "Guided"; + itemlist << "Loiter"; + itemlist << "RTL"; + itemlist << "Circle"; + itemlist << "Pos Hold"; + itemlist << "Land"; + itemlist << "OF_LOITER"; + itemlist << "Toy"; + ui.mode6ComboBox->setEnabled(true); + } + ui.mode1ComboBox->addItems(itemlist); + ui.mode2ComboBox->addItems(itemlist); + ui.mode3ComboBox->addItems(itemlist); + ui.mode4ComboBox->addItems(itemlist); + ui.mode5ComboBox->addItems(itemlist); + ui.mode6ComboBox->addItems(itemlist); +} +void FlightModeConfig::modeChanged(int sysId, QString status, QString description) +{ + //Unused? +} +void FlightModeConfig::saveButtonClicked() +{ + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + m_uas->getParamManager()->setParameter(1,"FLTMODE1",(char)planeModeUiIndexToIndex[ui.mode1ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE2",(char)planeModeUiIndexToIndex[ui.mode2ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE3",(char)planeModeUiIndexToIndex[ui.mode3ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE4",(char)planeModeUiIndexToIndex[ui.mode4ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE5",(char)planeModeUiIndexToIndex[ui.mode5ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE6",(char)planeModeUiIndexToIndex[ui.mode6ComboBox->currentIndex()]); + } + else if (m_uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + m_uas->getParamManager()->setParameter(1,"MODE1",(char)roverModeUiIndexToIndex[ui.mode1ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE2",(char)roverModeUiIndexToIndex[ui.mode2ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE3",(char)roverModeUiIndexToIndex[ui.mode3ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE4",(char)roverModeUiIndexToIndex[ui.mode4ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE5",(char)roverModeUiIndexToIndex[ui.mode5ComboBox->currentIndex()]); + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + m_uas->getParamManager()->setParameter(1,"FLTMODE1",(char)ui.mode1ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE2",(char)ui.mode2ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE3",(char)ui.mode3ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE4",(char)ui.mode4ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE5",(char)ui.mode5ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE6",(char)ui.mode6ComboBox->currentIndex()); + } +} + +void FlightModeConfig::remoteControlChannelRawChanged(int chan,float val) +{ + if (chan == 4) + { + //Channel 5 (0 array) is the mode switch. + ///TODO: Make this configurable + if (val <= 1230) + { + ui.mode1Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <= 1360) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <= 1490) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <=1620) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <=1749) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode6Label->setStyleSheet(""); + } + else + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + } + } +} + +void FlightModeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + if (parameterName == "FLTMODE1") + { + ui.mode1ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE2") + { + ui.mode2ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE3") + { + ui.mode3ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE4") + { + ui.mode4ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE5") + { + ui.mode5ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE6") + { + ui.mode6ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + } + else if (m_uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + if (parameterName == "MODE1") + { + ui.mode1ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE2") + { + ui.mode2ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE3") + { + ui.mode3ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE4") + { + ui.mode4ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE5") + { + ui.mode5ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + if (parameterName == "FLTMODE1") + { + ui.mode1ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE2") + { + ui.mode2ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE3") + { + ui.mode3ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE4") + { + ui.mode4ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE5") + { + ui.mode5ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE6") + { + ui.mode6ComboBox->setCurrentIndex(value.toInt()); + } + } +} diff --git a/src/ui/configuration/FlightModeConfig.h b/src/ui/configuration/FlightModeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..373de8560e02ee5259c4f1b7b45cd6247f203d3f --- /dev/null +++ b/src/ui/configuration/FlightModeConfig.h @@ -0,0 +1,31 @@ +#ifndef FLIGHTMODECONFIG_H +#define FLIGHTMODECONFIG_H + +#include +#include "ui_FlightModeConfig.h" +#include "UASInterface.h" +#include "UASManager.h" +#include "AP2ConfigWidget.h" + +class FlightModeConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit FlightModeConfig(QWidget *parent = 0); + ~FlightModeConfig(); +private slots: + void activeUASSet(UASInterface *uas); + void saveButtonClicked(); + void modeChanged(int sysId, QString status, QString description); + void remoteControlChannelRawChanged(int chan,float val); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap roverModeIndexToUiIndex; + QMap planeModeIndexToUiIndex; + QMap roverModeUiIndexToIndex; + QMap planeModeUiIndexToIndex; + Ui::FlightModeConfig ui; +}; + +#endif // FLIGHTMODECONFIG_H diff --git a/src/ui/configuration/FlightModeConfig.ui b/src/ui/configuration/FlightModeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..2cb8585bd3f0d3e4dcb4c18ff2d7e8aa574b3ec2 --- /dev/null +++ b/src/ui/configuration/FlightModeConfig.ui @@ -0,0 +1,264 @@ + + + FlightModeConfig + + + + 0 + 0 + 818 + 359 + + + + Form + + + + + 10 + 20 + 131 + 31 + + + + <h2>Flight Modes</h2> + + + false + + + + + + 20 + 70 + 481 + 191 + + + + + + + 8 + + + 0 + + + + + Flight Mode 1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 2 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 3 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 4 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 5 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 6 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + + + 0 + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + + + + + + + + PWM 0 - 1230 + + + + + + + PWM 1231 - 1360 + + + + + + + PWM 1361 - 1490 + + + + + + + PWM 1491 - 1620 + + + + + + + PWM 1621 - 1749 + + + + + + + + + + PWM 1750 + + + + + + + + + + + + 50 + 290 + 75 + 23 + + + + Save + + + + + + diff --git a/src/ui/configuration/FrameTypeConfig.cc b/src/ui/configuration/FrameTypeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..7ee5abad3ddd32ea2a241f04ffbb77ed3ca93bfc --- /dev/null +++ b/src/ui/configuration/FrameTypeConfig.cc @@ -0,0 +1,102 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Airframe type configuration widget source. + * + * @author Michael Carpenter + * + */ + +#include "FrameTypeConfig.h" + + +FrameTypeConfig::FrameTypeConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + + //Disable until we get a FRAME parameter. + ui.xRadioButton->setEnabled(false); + ui.vRadioButton->setEnabled(false); + ui.plusRadioButton->setEnabled(false); + + connect(ui.plusRadioButton,SIGNAL(clicked()),this,SLOT(plusFrameSelected())); + connect(ui.xRadioButton,SIGNAL(clicked()),this,SLOT(xFrameSelected())); + connect(ui.vRadioButton,SIGNAL(clicked()),this,SLOT(vFrameSelected())); +} + +FrameTypeConfig::~FrameTypeConfig() +{ +} +void FrameTypeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "FRAME") + { + ui.xRadioButton->setEnabled(true); + ui.vRadioButton->setEnabled(true); + ui.plusRadioButton->setEnabled(true); + if (value.toInt() == 0) + { + ui.plusRadioButton->setChecked(true); + } + else if (value.toInt() == 1) + { + ui.xRadioButton->setChecked(true); + } + else if (value.toInt() == 2) + { + ui.vRadioButton->setChecked(true); + } + } +} + +void FrameTypeConfig::xFrameSelected() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FRAME",QVariant(1)); +} + +void FrameTypeConfig::plusFrameSelected() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FRAME",QVariant(0)); +} + +void FrameTypeConfig::vFrameSelected() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FRAME",QVariant(2)); +} diff --git a/src/ui/configuration/FrameTypeConfig.h b/src/ui/configuration/FrameTypeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..92d04b95c50db05eb24233f20360ff672287da71 --- /dev/null +++ b/src/ui/configuration/FrameTypeConfig.h @@ -0,0 +1,57 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Airframe type configuration widget header. + * + * @author Michael Carpenter + * + */ + +#ifndef FRAMETYPECONFIG_H +#define FRAMETYPECONFIG_H + +#include +#include "ui_FrameTypeConfig.h" +#include "UASInterface.h" +#include "UASManager.h" +#include "QGCUASParamManager.h" +#include "AP2ConfigWidget.h" +class FrameTypeConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit FrameTypeConfig(QWidget *parent = 0); + ~FrameTypeConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void xFrameSelected(); + void plusFrameSelected(); + void vFrameSelected(); +private: + Ui::FrameTypeConfig ui; +}; + +#endif // FRAMETYPECONFIG_H diff --git a/src/ui/configuration/FrameTypeConfig.ui b/src/ui/configuration/FrameTypeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6787fa5dbc17d6f27fdfeeb689e766c4dc49b44d --- /dev/null +++ b/src/ui/configuration/FrameTypeConfig.ui @@ -0,0 +1,107 @@ + + + FrameTypeConfig + + + + 0 + 0 + 553 + 497 + + + + Form + + + + + + <h2>Frame Setup</h2> + + + false + + + + + + + + + 'Plus' Style + + + + :/files/images/mavs/frames_plus.png:/files/images/mavs/frames_plus.png + + + + 300 + 150 + + + + + + + + 'X' Style + + + + :/files/images/mavs/frames_x.png:/files/images/mavs/frames_x.png + + + + 300 + 150 + + + + + + + + Qt::LeftToRight + + + false + + + 'V' Style + + + + :/files/images/mavs/frames-05.png:/files/images/mavs/frames-05.png + + + + 300 + 120 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/src/ui/configuration/GeoFenceConfig.cc b/src/ui/configuration/GeoFenceConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..ea01a4b248aa781b46c20fa384402a0dbff6502d --- /dev/null +++ b/src/ui/configuration/GeoFenceConfig.cc @@ -0,0 +1,11 @@ +#include "GeoFenceConfig.h" + + +GeoFenceConfig::GeoFenceConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +GeoFenceConfig::~GeoFenceConfig() +{ +} diff --git a/src/ui/configuration/GeoFenceConfig.h b/src/ui/configuration/GeoFenceConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..71624346d7c009b4284bb06937bccfb5e7772026 --- /dev/null +++ b/src/ui/configuration/GeoFenceConfig.h @@ -0,0 +1,19 @@ +#ifndef GEOFENCECONFIG_H +#define GEOFENCECONFIG_H + +#include +#include "ui_GeoFenceConfig.h" + +class GeoFenceConfig : public QWidget +{ + Q_OBJECT + +public: + explicit GeoFenceConfig(QWidget *parent = 0); + ~GeoFenceConfig(); + +private: + Ui::GeoFenceConfig ui; +}; + +#endif // GEOFENCECONFIG_H diff --git a/src/ui/configuration/GeoFenceConfig.ui b/src/ui/configuration/GeoFenceConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..b51ea2e5083aa2ffe8cedff24cf37228206d76a8 --- /dev/null +++ b/src/ui/configuration/GeoFenceConfig.ui @@ -0,0 +1,32 @@ + + + GeoFenceConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 141 + 51 + + + + <h2>Geo Fence</h2> + + + + + + diff --git a/src/ui/configuration/OpticalFlowConfig.cc b/src/ui/configuration/OpticalFlowConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..cc0404a06d4418511ef2dfe78fe742cd1ecf0106 --- /dev/null +++ b/src/ui/configuration/OpticalFlowConfig.cc @@ -0,0 +1,36 @@ +#include "OpticalFlowConfig.h" +#include + +OpticalFlowConfig::OpticalFlowConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.enableCheckBox,SIGNAL(clicked(bool)),this,SLOT(enableCheckBoxClicked(bool))); +} + +OpticalFlowConfig::~OpticalFlowConfig() +{ +} +void OpticalFlowConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "FLOW_ENABLE") + { + if (value.toInt() == 0) + { + ui.enableCheckBox->setChecked(false); + } + else + { + ui.enableCheckBox->setChecked(true); + } + } +} + +void OpticalFlowConfig::enableCheckBoxClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FLOW_ENABLE",checked ? 1 : 0); +} diff --git a/src/ui/configuration/OpticalFlowConfig.h b/src/ui/configuration/OpticalFlowConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..38b4ae7ebb83f565a80a315ad11d870bf89fc0f3 --- /dev/null +++ b/src/ui/configuration/OpticalFlowConfig.h @@ -0,0 +1,22 @@ +#ifndef OPTICALFLOWCONFIG_H +#define OPTICALFLOWCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_OpticalFlowConfig.h" + +class OpticalFlowConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit OpticalFlowConfig(QWidget *parent = 0); + ~OpticalFlowConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void enableCheckBoxClicked(bool checked); +private: + Ui::OpticalFlowConfig ui; +}; + +#endif // OPTICALFLOWCONFIG_H diff --git a/src/ui/configuration/OpticalFlowConfig.ui b/src/ui/configuration/OpticalFlowConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..e5a5bce4c6406af6cb060bce8447517871586632 --- /dev/null +++ b/src/ui/configuration/OpticalFlowConfig.ui @@ -0,0 +1,69 @@ + + + OpticalFlowConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>Optical Flow</h2> + + + false + + + + + + 100 + 60 + 70 + 17 + + + + Enable + + + + + + 10 + 60 + 81 + 71 + + + + + + + :/files/images/devices/BR-0016-01-3T.jpg + + + true + + + + + + + + diff --git a/src/ui/configuration/OsdConfig.cc b/src/ui/configuration/OsdConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..766c9b0edb30843c6131e0ed0818cbd6b5cc2a30 --- /dev/null +++ b/src/ui/configuration/OsdConfig.cc @@ -0,0 +1,37 @@ +#include "OsdConfig.h" +#include + +OsdConfig::OsdConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.enablePushButton,SIGNAL(clicked()),this,SLOT(enableButtonClicked())); +} + +OsdConfig::~OsdConfig() +{ +} +void OsdConfig::enableButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"SR0_EXT_STAT",2); + m_uas->getParamManager()->setParameter(1,"SR0_EXTRA1",10); + m_uas->getParamManager()->setParameter(1,"SR0_EXTRA2",10); + m_uas->getParamManager()->setParameter(1,"SR0_EXTRA3",2); + m_uas->getParamManager()->setParameter(1,"SR0_POSITION",3); + m_uas->getParamManager()->setParameter(1,"SR0_RAW_CTRL",2); + m_uas->getParamManager()->setParameter(1,"SR0_RAW_SENS",2); + m_uas->getParamManager()->setParameter(1,"SR0_RC_CHAN",2); + + m_uas->getParamManager()->setParameter(1,"SR3_EXT_STAT",2); + m_uas->getParamManager()->setParameter(1,"SR3_EXTRA1",10); + m_uas->getParamManager()->setParameter(1,"SR3_EXTRA2",10); + m_uas->getParamManager()->setParameter(1,"SR3_EXTRA3",2); + m_uas->getParamManager()->setParameter(1,"SR3_POSITION",3); + m_uas->getParamManager()->setParameter(1,"SR3_RAW_CTRL",2); + m_uas->getParamManager()->setParameter(1,"SR3_RAW_SENS",2); + m_uas->getParamManager()->setParameter(1,"SR3_RC_CHAN",2); +} diff --git a/src/ui/configuration/OsdConfig.h b/src/ui/configuration/OsdConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..963fa0dd1a507b8f1d0f1a4e9ad072326d11512b --- /dev/null +++ b/src/ui/configuration/OsdConfig.h @@ -0,0 +1,21 @@ +#ifndef OSDCONFIG_H +#define OSDCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_OsdConfig.h" + +class OsdConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit OsdConfig(QWidget *parent = 0); + ~OsdConfig(); +private slots: + void enableButtonClicked(); +private: + Ui::OsdConfig ui; +}; + +#endif // OSDCONFIG_H diff --git a/src/ui/configuration/OsdConfig.ui b/src/ui/configuration/OsdConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6c9e4d7aece4e8246d56d24fd691a2e4e06b94d6 --- /dev/null +++ b/src/ui/configuration/OsdConfig.ui @@ -0,0 +1,85 @@ + + + OsdConfig + + + + 0 + 0 + 499 + 243 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>OSD</h2> + + + false + + + + + + 10 + 60 + 101 + 41 + + + + + + + :/files/images/devices/MinimOSD.jpg + + + true + + + + + + 230 + 60 + 191 + 41 + + + + You only need to use this if you are +having issue with your OSD not +updating + + + + + + 120 + 60 + 91 + 41 + + + + Enable +Telemetry + + + + + + + + diff --git a/src/ui/configuration/ParamWidget.cc b/src/ui/configuration/ParamWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..93b3bfd26455959198253a45956f129a8af155f8 --- /dev/null +++ b/src/ui/configuration/ParamWidget.cc @@ -0,0 +1,79 @@ +#include "ParamWidget.h" + + +ParamWidget::ParamWidget(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +ParamWidget::~ParamWidget() +{ +} + +void ParamWidget::setupInt(QString title,QString description,int value,int min,int max) +{ + type = INT; + ui.titleLabel->setText("

" + title + "

"); + ui.descriptionLabel->setText(description); + ui.valueComboBox->hide(); + ui.valueSlider->show(); + ui.intSpinBox->show(); + ui.doubleSpinBox->hide(); + m_min = min; + m_max = max; +} + +void ParamWidget::setupDouble(QString title,QString description,double value,double min,double max) +{ + type = DOUBLE; + ui.titleLabel->setText("

" + title + "

"); + ui.descriptionLabel->setText(description); + ui.valueComboBox->hide(); + ui.valueSlider->show(); + ui.intSpinBox->hide(); + ui.doubleSpinBox->show(); + m_min = min; + m_max = max; +} + +void ParamWidget::setupCombo(QString title,QString description,QList > list) +{ + type = COMBO; + ui.titleLabel->setText("

" + title + "

"); + ui.descriptionLabel->setText(description); + ui.valueComboBox->show(); + ui.valueSlider->hide(); + ui.intSpinBox->hide(); + ui.doubleSpinBox->hide(); + m_valueList = list; + ui.valueComboBox->clear(); + for (int i=0;iaddItem(m_valueList[i].second); + } +} + +void ParamWidget::setValue(double value) +{ + if (type == INT) + { + ui.intSpinBox->setValue(value); + ui.valueSlider->setValue(((value + m_min) / (m_max + m_min)) * 100.0); + } + else if (type == DOUBLE) + { + ui.doubleSpinBox->setValue(value); + ui.valueSlider->setValue(((value + m_min) / (m_max + m_min)) * 100.0); + } + else if (type == COMBO) + { + for (int i=0;isetCurrentIndex(i); + return; + } + } + } +} diff --git a/src/ui/configuration/ParamWidget.h b/src/ui/configuration/ParamWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..aa375d296752f2d2cc9c052d8b5d60a3b9ec2c35 --- /dev/null +++ b/src/ui/configuration/ParamWidget.h @@ -0,0 +1,34 @@ +#ifndef PARAMWIDGET_H +#define PARAMWIDGET_H + +#include +#include "ui_ParamWidget.h" + +class ParamWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ParamWidget(QWidget *parent = 0); + ~ParamWidget(); + void setupInt(QString title,QString description,int value,int min,int max); + void setupDouble(QString title,QString description,double value,double min,double max); + void setupCombo(QString title,QString description,QList > list); + void setValue(double value); +private: + enum VIEWTYPE + { + INT, + DOUBLE, + COMBO + }; + double m_min; + double m_max; + double m_dvalue; + int m_ivalue; + VIEWTYPE type; + QList > m_valueList; + Ui::ParamWidget ui; +}; + +#endif // PARAMWIDGET_H diff --git a/src/ui/configuration/ParamWidget.ui b/src/ui/configuration/ParamWidget.ui new file mode 100644 index 0000000000000000000000000000000000000000..ddf4653b8f09169cdc55b6e2edad622e647743c7 --- /dev/null +++ b/src/ui/configuration/ParamWidget.ui @@ -0,0 +1,78 @@ + + + ParamWidget + + + + 0 + 0 + 619 + 207 + + + + Form + + + + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + diff --git a/src/ui/configuration/Radio3DRConfig.cc b/src/ui/configuration/Radio3DRConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..435ae290f92f2bc05c417f86c3c8716b810a2946 --- /dev/null +++ b/src/ui/configuration/Radio3DRConfig.cc @@ -0,0 +1,11 @@ +#include "Radio3DRConfig.h" + + +Radio3DRConfig::Radio3DRConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +Radio3DRConfig::~Radio3DRConfig() +{ +} diff --git a/src/ui/configuration/Radio3DRConfig.h b/src/ui/configuration/Radio3DRConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..5233921d1592ca7aae68fbe9642c2a9c08fa3708 --- /dev/null +++ b/src/ui/configuration/Radio3DRConfig.h @@ -0,0 +1,19 @@ +#ifndef RADIO3DRCONFIG_H +#define RADIO3DRCONFIG_H + +#include +#include "ui_Radio3DRConfig.h" + +class Radio3DRConfig : public QWidget +{ + Q_OBJECT + +public: + explicit Radio3DRConfig(QWidget *parent = 0); + ~Radio3DRConfig(); + +private: + Ui::Radio3DRConfig ui; +}; + +#endif // RADIO3DRCONFIG_H diff --git a/src/ui/configuration/Radio3DRConfig.ui b/src/ui/configuration/Radio3DRConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..7a98b9dba7db8ce30c2de14706483a9924b6076d --- /dev/null +++ b/src/ui/configuration/Radio3DRConfig.ui @@ -0,0 +1,35 @@ + + + Radio3DRConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>3DR Radio</h2> + + + false + + + + + + diff --git a/src/ui/configuration/RadioCalibrationConfig.cc b/src/ui/configuration/RadioCalibrationConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..067a56fc14d3db74a3b18eb439d915e351181cb9 --- /dev/null +++ b/src/ui/configuration/RadioCalibrationConfig.cc @@ -0,0 +1,236 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Radio Calibration Configuration source. + * + * @author Michael Carpenter + * + */ + +#include "RadioCalibrationConfig.h" +#include + +RadioCalibrationConfig::RadioCalibrationConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + + connect(ui.calibrateButton,SIGNAL(clicked()),this,SLOT(calibrateButtonClicked())); + m_calibrationEnabled = false; + ui.rollWidget->setMin(800); + ui.rollWidget->setMax(2200); + ui.pitchWidget->setMin(800); + ui.pitchWidget->setMax(2200); + ui.throttleWidget->setMin(800); + ui.throttleWidget->setMax(2200); + ui.yawWidget->setMin(800); + ui.yawWidget->setMax(2200); + ui.radio5Widget->setMin(800); + ui.radio5Widget->setMax(2200); + ui.radio6Widget->setMin(800); + ui.radio6Widget->setMax(2200); + ui.radio7Widget->setMin(800); + ui.radio7Widget->setMax(2200); + ui.radio8Widget->setMin(800); + ui.radio8Widget->setMax(2200); + ui.rollWidget->setOrientation(Qt::Horizontal); + ui.rollWidget->setName("Roll"); + ui.yawWidget->setOrientation(Qt::Horizontal); + ui.yawWidget->setName("Yaw"); + ui.pitchWidget->setName("Pitch"); + ui.throttleWidget->setName("Throttle"); + ui.radio5Widget->setOrientation(Qt::Horizontal); + ui.radio5Widget->setName("Radio 5"); + ui.radio6Widget->setOrientation(Qt::Horizontal); + ui.radio6Widget->setName("Radio 6"); + ui.radio7Widget->setOrientation(Qt::Horizontal); + ui.radio7Widget->setName("Radio 7"); + ui.radio8Widget->setOrientation(Qt::Horizontal); + ui.radio8Widget->setName("Radio 8"); + + guiUpdateTimer = new QTimer(this); + connect(guiUpdateTimer,SIGNAL(timeout()),this,SLOT(guiUpdateTimerTick())); +} + +RadioCalibrationConfig::~RadioCalibrationConfig() +{ +} +void RadioCalibrationConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas, SIGNAL(remoteControlChannelRawChanged(int,float)), this,SLOT(remoteControlChannelRawChanged(int,float))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanged(int,float))); +} +void RadioCalibrationConfig::remoteControlChannelRawChanged(int chan,float val) +{ + + //Channel is 0-7 typically? + //Val will be 0-3000, PWM value. + if (m_calibrationEnabled) { + if (val < rcMin[chan]) + { + rcMin[chan] = val; + } + + if (val > rcMax[chan]) + { + rcMax[chan] = val; + } + } + + // Raw value + rcValue[chan] = val; +} + +void RadioCalibrationConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + +} +void RadioCalibrationConfig::guiUpdateTimerTick() +{ + ui.rollWidget->setValue(rcValue[0]); + ui.pitchWidget->setValue(rcValue[1]); + ui.throttleWidget->setValue(rcValue[2]); + ui.yawWidget->setValue(rcValue[3]); + ui.radio5Widget->setValue(rcValue[4]); + ui.radio6Widget->setValue(rcValue[5]); + ui.radio7Widget->setValue(rcValue[6]); + ui.radio8Widget->setValue(rcValue[7]); + if (m_calibrationEnabled) + { + ui.rollWidget->setMin(rcMin[0]); + ui.rollWidget->setMax(rcMax[0]); + ui.pitchWidget->setMin(rcMin[1]); + ui.pitchWidget->setMax(rcMax[1]); + ui.throttleWidget->setMin(rcMin[2]); + ui.throttleWidget->setMax(rcMax[2]); + ui.yawWidget->setMin(rcMin[3]); + ui.yawWidget->setMax(rcMax[3]); + ui.radio5Widget->setMin(rcMin[4]); + ui.radio5Widget->setMax(rcMax[4]); + ui.radio6Widget->setMin(rcMin[5]); + ui.radio6Widget->setMax(rcMax[5]); + ui.radio7Widget->setMin(rcMin[6]); + ui.radio7Widget->setMax(rcMax[6]); + ui.radio8Widget->setMin(rcMin[7]); + ui.radio8Widget->setMax(rcMax[7]); + } +} +void RadioCalibrationConfig::showEvent(QShowEvent *event) +{ + guiUpdateTimer->start(100); +} +void RadioCalibrationConfig::hideEvent(QHideEvent *event) +{ + guiUpdateTimer->stop(); +} +void RadioCalibrationConfig::calibrateButtonClicked() +{ + if (!m_calibrationEnabled) + { + ui.calibrateButton->setText("End Calibration"); + QMessageBox::information(0,"Warning!","You are about to start radio calibration.\nPlease ensure all motor power is disconnected AND all props are removed from the vehicle.\nAlso ensure transmitter and reciever are powered and connected\n\nClick OK to confirm"); + m_calibrationEnabled = true; + for (int i=0;i<8;i++) + { + rcMin[i] = 1500; + rcMax[i] = 1500; + } + ui.rollWidget->showMinMax(); + ui.pitchWidget->showMinMax(); + ui.yawWidget->showMinMax(); + ui.radio5Widget->showMinMax(); + ui.radio6Widget->showMinMax(); + ui.radio7Widget->showMinMax(); + ui.radio8Widget->showMinMax(); + QMessageBox::information(0,"Information","Click OK, then move all sticks to their extreme positions, watching the min/max values to ensure you get the most range from your controller. This includes all switches"); + } + else + { + ui.calibrateButton->setText("Calibrate"); + QMessageBox::information(0,"Trims","Ensure all sticks are centered and throttle is in the downmost position, click OK to continue"); + ///TODO: Set trims! + m_calibrationEnabled = false; + ui.rollWidget->hideMinMax(); + ui.pitchWidget->hideMinMax(); + ui.yawWidget->hideMinMax(); + ui.radio5Widget->hideMinMax(); + ui.radio6Widget->hideMinMax(); + ui.radio7Widget->hideMinMax(); + ui.radio8Widget->hideMinMax(); + QString statusstr; + statusstr = "Below you will find the detected radio calibration information that will be sent to the autopilot\n"; + statusstr += "Normal values are around 1100 to 1900, with disconnected channels reading very close to 1500\n\n"; + statusstr += "Channel\tMin\tCenter\tMax\n"; + statusstr += "--------------------\n"; + for (int i=0;i<8;i++) + { + statusstr += QString::number(i) + "\t" + QString::number(rcMin[i]) + "\t" + QString::number(rcValue[i]) + "\t" + QString::number(rcMax[i]) + "\n"; + } + QMessageBox::information(0,"Status",statusstr); + //Send calibrations. + QString minTpl("RC%1_MIN"); + QString maxTpl("RC%1_MAX"); + //QString trimTpl("RC%1_TRIM"); + + // Do not write the RC type, as these values depend on this + // active onboard parameter + + for (unsigned int i = 0; i < 8; ++i) + { + qDebug() << "SENDING MIN" << minTpl.arg(i+1) << rcMin[i]; + qDebug() << "SENDING MAX" << maxTpl.arg(i+1) << rcMax[i]; + m_uas->getParamManager()->setParameter(1, minTpl.arg(i+1), (float)rcMin[i]); + QGC::SLEEP::usleep(50000); + //m_uas->setParameter(0, trimTpl.arg(i+1), rcTrim[i]); + //QGC::SLEEP::usleep(50000); + m_uas->getParamManager()->setParameter(1, maxTpl.arg(i+1), (float)rcMax[i]); + QGC::SLEEP::usleep(50000); + } + ui.rollWidget->setMin(800); + ui.rollWidget->setMax(2200); + ui.pitchWidget->setMin(800); + ui.pitchWidget->setMax(2200); + ui.throttleWidget->setMin(800); + ui.throttleWidget->setMax(2200); + ui.yawWidget->setMin(800); + ui.yawWidget->setMax(2200); + ui.radio5Widget->setMin(800); + ui.radio5Widget->setMax(2200); + ui.radio6Widget->setMin(800); + ui.radio6Widget->setMax(2200); + ui.radio7Widget->setMin(800); + ui.radio7Widget->setMax(2200); + ui.radio8Widget->setMin(800); + ui.radio8Widget->setMax(2200); + + } +} diff --git a/src/ui/configuration/RadioCalibrationConfig.h b/src/ui/configuration/RadioCalibrationConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..00b90f8e20970fd1f2b3d7bf313149727f741758 --- /dev/null +++ b/src/ui/configuration/RadioCalibrationConfig.h @@ -0,0 +1,73 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Radio Calibration Configuration widget header. + * + * @author Michael Carpenter + * + */ + +#ifndef RADIOCALIBRATIONCONFIG_H +#define RADIOCALIBRATIONCONFIG_H + +#include +#include +#include +#include +#include "ui_RadioCalibrationConfig.h" +#include "UASManager.h" +#include "UASInterface.h" +#include "AP2ConfigWidget.h" +class RadioCalibrationConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit RadioCalibrationConfig(QWidget *parent = 0); + ~RadioCalibrationConfig(); +protected: + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); +private slots: + void activeUASSet(UASInterface *uas); + void remoteControlChannelRawChanged(int chan,float val); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void guiUpdateTimerTick(); + void calibrateButtonClicked(); +private: + QList rcMin; + QList rcMax; + QList rcTrim; + QList rcValue; + //double rcMin[8]; + //double rcMax[8]; + //double rcTrim[8]; + //double rcValue[8]; + QTimer *guiUpdateTimer; + bool m_calibrationEnabled; + Ui::RadioCalibrationConfig ui; +}; + +#endif // RADIOCALIBRATIONCONFIG_H diff --git a/src/ui/configuration/RadioCalibrationConfig.ui b/src/ui/configuration/RadioCalibrationConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..ccf80621198ef28a53d60e967e397d0e811d5bb5 --- /dev/null +++ b/src/ui/configuration/RadioCalibrationConfig.ui @@ -0,0 +1,280 @@ + + + RadioCalibrationConfig + + + + 0 + 0 + 771 + 389 + + + + Form + + + + + 10 + 10 + 171 + 31 + + + + <h2>Radio Calibration</h2> + + + false + + + + + + 10 + 50 + 716 + 300 + + + + + QLayout::SetMinAndMaxSize + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 50 + 200 + + + + + 50 + 200 + + + + + + + + Qt::Horizontal + + + + 250 + 20 + + + + + + + + + 50 + 200 + + + + + 50 + 200 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 20 + 360 + 91 + 23 + + + + Calibrate + + + + + + QGCRadioChannelDisplay + QWidget +
ui/designer/QGCRadioChannelDisplay.h
+ 1 +
+
+ + +
diff --git a/src/ui/configuration/SonarConfig.cc b/src/ui/configuration/SonarConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..586a7f9ab5d37d7e1d1be3ff2df88f986421c95b --- /dev/null +++ b/src/ui/configuration/SonarConfig.cc @@ -0,0 +1,67 @@ +#include "SonarConfig.h" +#include + +SonarConfig::SonarConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.sonarTypeComboBox->addItem("XL-EZ0 / XL-EZ4"); + ui.sonarTypeComboBox->addItem("LV-EZ0"); + ui.sonarTypeComboBox->addItem("XL-EZL0"); + ui.sonarTypeComboBox->addItem("HRLV"); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + connect(ui.sonarTypeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sonarTypeChanged(int))); +} + +SonarConfig::~SonarConfig() +{ +} +void SonarConfig::checkBoxToggled(bool enabled) +{ + if (enabled) + { + ui.sonarTypeComboBox->setEnabled(false); + } + if (!m_uas) + { + QMessageBox::information(0,tr("Error"),tr("Please connect to a MAV before attempting to set configuration")); + return; + } + m_uas->getParamManager()->setParameter(1,"SONAR_ENABLE",ui.enableCheckBox->isChecked() ? 1 : 0); +} +void SonarConfig::sonarTypeChanged(int index) +{ + if (!m_uas) + { + QMessageBox::information(0,tr("Error"),tr("Please connect to a MAV before attempting to set configuration")); + return; + } + m_uas->getParamManager()->setParameter(1,"SONAR_TYPE",ui.sonarTypeComboBox->currentIndex()); +} + +void SonarConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "SONAR_ENABLE") + { + if (value.toInt() == 0) + { + //Disabled + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.enableCheckBox->setChecked(false); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.sonarTypeComboBox->setEnabled(false); + } + else + { + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.enableCheckBox->setChecked(true); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.sonarTypeComboBox->setEnabled(true); + } + } + else if (parameterName == "SONAR_TYPE") + { + disconnect(ui.sonarTypeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sonarTypeChanged(int))); + ui.sonarTypeComboBox->setCurrentIndex(value.toInt()); + connect(ui.sonarTypeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sonarTypeChanged(int))); + } +} diff --git a/src/ui/configuration/SonarConfig.h b/src/ui/configuration/SonarConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..825591a65294e37f5359675d715103031bf601c9 --- /dev/null +++ b/src/ui/configuration/SonarConfig.h @@ -0,0 +1,23 @@ +#ifndef SONARCONFIG_H +#define SONARCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_SonarConfig.h" + +class SonarConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit SonarConfig(QWidget *parent = 0); + ~SonarConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void checkBoxToggled(bool enabled); + void sonarTypeChanged(int index); +private: + Ui::SonarConfig ui; +}; + +#endif // SONARCONFIG_H diff --git a/src/ui/configuration/SonarConfig.ui b/src/ui/configuration/SonarConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..7c40d028ce6c772db234b8972473c3ed906b7019 --- /dev/null +++ b/src/ui/configuration/SonarConfig.ui @@ -0,0 +1,79 @@ + + + SonarConfig + + + + 0 + 0 + 651 + 432 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>Sonar</h2> + + + false + + + + + + 30 + 60 + 91 + 81 + + + + + + + :/files/images/devices/AC-0004-11-2.jpg + + + true + + + + + + 140 + 60 + 70 + 17 + + + + Enable + + + + + + 150 + 100 + 171 + 22 + + + + + + + + + diff --git a/src/ui/configuration/StandardParamConfig.cc b/src/ui/configuration/StandardParamConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..c9ebb4acf9718cda6cddcf7095a13e2b9b037f08 --- /dev/null +++ b/src/ui/configuration/StandardParamConfig.cc @@ -0,0 +1,33 @@ +#include "StandardParamConfig.h" +#include "ParamWidget.h" +StandardParamConfig::StandardParamConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); +} +StandardParamConfig::~StandardParamConfig() +{ +} +void StandardParamConfig::addRange(QString title,QString description,QString param,double min,double max) +{ + ParamWidget *widget = new ParamWidget(ui.scrollAreaWidgetContents); + paramToWidgetMap[param] = widget; + widget->setupDouble(title + "(" + param + ")",description,0,min,max); + ui.verticalLayout->addWidget(widget); + widget->show(); +} + +void StandardParamConfig::addCombo(QString title,QString description,QString param,QList > valuelist) +{ + ParamWidget *widget = new ParamWidget(ui.scrollAreaWidgetContents); + paramToWidgetMap[param] = widget; + widget->setupCombo(title + "(" + param + ")",description,valuelist); + ui.verticalLayout->addWidget(widget); + widget->show(); +} +void StandardParamConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (paramToWidgetMap.contains(parameterName)) + { + paramToWidgetMap[parameterName]->setValue(value.toDouble()); + } +} diff --git a/src/ui/configuration/StandardParamConfig.h b/src/ui/configuration/StandardParamConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..b2fbc04f484b25c33e80b79c10ada6484ac9d252 --- /dev/null +++ b/src/ui/configuration/StandardParamConfig.h @@ -0,0 +1,24 @@ +#ifndef STANDARDPARAMCONFIG_H +#define STANDARDPARAMCONFIG_H + +#include +#include "ui_StandardParamConfig.h" +#include "AP2ConfigWidget.h" +#include "ParamWidget.h" +class StandardParamConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit StandardParamConfig(QWidget *parent = 0); + ~StandardParamConfig(); + void addRange(QString title,QString description,QString param,double min,double max); + void addCombo(QString title,QString description,QString param,QList > valuelist); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap paramToWidgetMap; + Ui::StandardParamConfig ui; +}; + +#endif // STANDARDPARAMCONFIG_H diff --git a/src/ui/configuration/StandardParamConfig.ui b/src/ui/configuration/StandardParamConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..53a96d984792d7aa6198efe9bfb7f3864b57c523 --- /dev/null +++ b/src/ui/configuration/StandardParamConfig.ui @@ -0,0 +1,50 @@ + + + StandardParamConfig + + + + 0 + 0 + 651 + 552 + + + + Form + + + + + + <h2>Standard Params</h2> + + + + + + + true + + + + + 0 + 0 + 631 + 505 + + + + + + + + + + + + + + + diff --git a/src/ui/uas/UASQuickView.cc b/src/ui/uas/UASQuickView.cc index 13a198f96a0452f577d40d74db31556549ba821b..9d5f428595c2f277abc378839026b4a908e40956 100644 --- a/src/ui/uas/UASQuickView.cc +++ b/src/ui/uas/UASQuickView.cc @@ -21,6 +21,7 @@ UASQuickView::UASQuickView(QWidget *parent) : this->setContextMenuPolicy(Qt::ActionsContextMenu); loadSettings(); + //If we don't have any predefined settings, set some defaults. if (uasPropertyValueMap.size() == 0) { @@ -40,6 +41,14 @@ UASQuickView::UASQuickView(QWidget *parent) : connect(updateTimer,SIGNAL(timeout()),this,SLOT(updateTimerTick())); } +UASQuickView::~UASQuickView() +{ + if (quickViewSelectDialog) + { + delete quickViewSelectDialog; + } +} + void UASQuickView::actionTriggered() { if (quickViewSelectDialog) diff --git a/src/ui/uas/UASQuickView.h b/src/ui/uas/UASQuickView.h index 943fa8c66542f000b2d84d45a0782ce45e7622ae..c60611249781b426e147040f3260ae9944f8b437 100644 --- a/src/ui/uas/UASQuickView.h +++ b/src/ui/uas/UASQuickView.h @@ -15,6 +15,7 @@ class UASQuickView : public QWidget Q_OBJECT public: UASQuickView(QWidget *parent = 0); + ~UASQuickView(); void addSource(MAVLinkDecoder *decoder); private: /** diff --git a/src/ui/uas/UASQuickViewItemSelect.cc b/src/ui/uas/UASQuickViewItemSelect.cc index 537d1aafb2b7d8ad14be0858f0f475820807ad98..6536529cae513debfa7dc251e0e1489eff3c9fe1 100644 --- a/src/ui/uas/UASQuickViewItemSelect.cc +++ b/src/ui/uas/UASQuickViewItemSelect.cc @@ -6,24 +6,76 @@ UASQuickViewItemSelect::UASQuickViewItemSelect(QWidget *parent) : QWidget(parent ui.setupUi(this); currcol = 0; currrow = 0; + ui.gridLayout->setSpacing(5); + ui.gridLayout->setMargin(0); } void UASQuickViewItemSelect::addItem(QString item,bool enabled) { + QString category = "."; + QString name = item; + if (item.indexOf(":") != -1 && item.indexOf(".") != -1) + { + //Item has a subcateogry + category = item.mid(item.indexOf(":")+1,item.indexOf(".") - item.indexOf(":")-1); + name = item.mid(item.indexOf(".")+1); + } + int col = -1; + if (m_categoryToIndexMap.contains(category)) + { + col = m_categoryToIndexMap[category]; + } + else + { + m_categoryToIndexMap[category] = currcol++; + col = m_categoryToIndexMap[category]; + //New column. + QLabel *titlelabel = new QLabel(this); + titlelabel->setText(category); + titlelabel->show(); + ui.gridLayout->addWidget(titlelabel,0,col); + } QCheckBox *label = new QCheckBox(this); + m_checkboxToValueMap[label] = item; + m_checkBoxList.append(label); if (enabled) { label->setChecked(true); } connect(label,SIGNAL(clicked(bool)),this,SLOT(checkBoxClicked(bool))); - label->setText(item); + label->setText(name); label->show(); - ui.gridLayout->addWidget(label,currrow,currcol++); - if (currcol > 10) + //ui.gridLayout->addWidget(label,currrow,currcol++); + bool breakout = false; + int row = -1; + while (!breakout) + { + if (!ui.gridLayout->itemAtPosition(++row,col) || row > 100) + { + breakout = true; + } + } + //Row is the next invalid object, and col is the proper column. + ui.gridLayout->addWidget(label,row,col); +} +void UASQuickViewItemSelect::resizeEvent(QResizeEvent *event) +{ + /*for (int i=0;iremoveWidget(m_checkBoxList[i]); } + int row = 0; + int col = 0; + for (int i=0;iaddWidget(m_checkBoxList[i],row,col); + col++; + ui.gridLayout->widget()->width() > this->width(); + //need to reduce column number. + + }*/ + } + void UASQuickViewItemSelect::checkBoxClicked(bool checked) { QCheckBox *check = qobject_cast(sender()); @@ -31,13 +83,19 @@ void UASQuickViewItemSelect::checkBoxClicked(bool checked) { return; } + QString checkval = check->text(); + if (m_checkboxToValueMap.contains(check)) + { + checkval = m_checkboxToValueMap[check]; + } if (checked) { - emit valueEnabled(check->text()); + + emit valueEnabled(checkval); } else { - emit valueDisabled(check->text()); + emit valueDisabled(checkval); } } diff --git a/src/ui/uas/UASQuickViewItemSelect.h b/src/ui/uas/UASQuickViewItemSelect.h index 4be402c5e1530f342594a0671cfd6393a234d93f..efd769cb3ae5930674bf4937110bcfbe44fdd3eb 100644 --- a/src/ui/uas/UASQuickViewItemSelect.h +++ b/src/ui/uas/UASQuickViewItemSelect.h @@ -2,6 +2,7 @@ #define UASQUICKVIEWITEMSELECT_H #include +#include #include "ui_UASQuickViewItemSelect.h" class UASQuickViewItemSelect : public QWidget @@ -14,7 +15,12 @@ public: void addItem(QString item,bool enabled = false); int currrow; int currcol; +protected: + void resizeEvent(QResizeEvent *event); private: + QMap m_categoryToIndexMap; + QMap m_checkboxToValueMap; + QList m_checkBoxList; Ui::UASQuickViewItemSelect ui; private slots: void checkBoxClicked(bool checked); diff --git a/src/ui/uas/UASQuickViewItemSelect.ui b/src/ui/uas/UASQuickViewItemSelect.ui index 9a35660c0e1beab619198e580ca1ff78dc059e7b..5371e2248ddf8881a6a03948a8d2808e34279025 100644 --- a/src/ui/uas/UASQuickViewItemSelect.ui +++ b/src/ui/uas/UASQuickViewItemSelect.ui @@ -6,12 +6,12 @@ 0 0 - 571 - 474 + 947 + 248
- Form + Select Item @@ -24,14 +24,27 @@ 0 0 - 551 - 454 + 927 + 228 - + + + + + Qt::Vertical + + + + 20 + 40 + + + +
diff --git a/src/ui/uas/UASQuickViewTextItem.cc b/src/ui/uas/UASQuickViewTextItem.cc index 520ad948e9e1719eac57dc34187c5b3f6288251f..bdac05135af8beb0706251d0cdf42cf4a0caf7b4 100644 --- a/src/ui/uas/UASQuickViewTextItem.cc +++ b/src/ui/uas/UASQuickViewTextItem.cc @@ -1,5 +1,6 @@ #include "UASQuickViewTextItem.h" #include +#include UASQuickViewTextItem::UASQuickViewTextItem(QWidget *parent) : UASQuickViewItem(parent) { // Set a standard vertical layout. @@ -9,20 +10,33 @@ UASQuickViewTextItem::UASQuickViewTextItem(QWidget *parent) : UASQuickViewItem(p // Create the title label. Scale the font based on available size. titleLabel = new QLabel(this); - titleLabel->setAlignment(Qt::AlignHCenter); - titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); - titleLabel->setObjectName(QString::fromUtf8("title")); - QFont titlefont = titleLabel->font(); - titlefont.setPixelSize(this->height() / 4.0); - titleLabel->setFont(titlefont); - layout->addWidget(titleLabel); +// <<<<<<< HEAD + titleLabel->setAlignment(Qt::AlignHCenter); + titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); + titleLabel->setObjectName(QString::fromUtf8("title")); + QFont titlefont = titleLabel->font(); + titlefont.setPixelSize(this->height() / 4.0); + titleLabel->setFont(titlefont); + layout->addWidget(titleLabel); - // Create the value label. Scale the font based on available size. - valueLabel = new QLabel(this); - valueLabel->setAlignment(Qt::AlignHCenter); - valueLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); - valueLabel->setObjectName(QString::fromUtf8("value")); - valueLabel->setText("0.00"); + // Create the value label. Scale the font based on available size. + valueLabel = new QLabel(this); + valueLabel->setAlignment(Qt::AlignHCenter); + valueLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); + valueLabel->setObjectName(QString::fromUtf8("value")); + valueLabel->setText("0.00"); +// ======= +// titleLabel->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored); +// titleLabel->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); +// this->layout()->addWidget(titleLabel); +// valueLabel = new QLabel(this); +// valueLabel->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored); +// valueLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); +// valueLabel->setText("0.00"); +// this->layout()->addWidget(valueLabel); +// //spacerItem = new QSpacerItem(20,40,QSizePolicy::Minimum,QSizePolicy::Ignored); +// //layout->addSpacerItem(spacerItem); +// >>>>>>> 34eaf1fb422146f5df3b01fad4d756343b3127c9 QFont valuefont = valueLabel->font(); valuefont.setPixelSize(this->height() / 2.0); valueLabel->setFont(valuefont); @@ -39,14 +53,52 @@ void UASQuickViewTextItem::setValue(double value) void UASQuickViewTextItem::setTitle(QString title) { - titleLabel->setText(title); + if (title.indexOf(".") != -1 && title.indexOf(":") != -1) + { + titleLabel->setText(title.mid(title.indexOf(".")+1)); + } + else + { + titleLabel->setText(title); + } } void UASQuickViewTextItem::resizeEvent(QResizeEvent *event) { QFont valuefont = valueLabel->font(); QFont titlefont = titleLabel->font(); - valuefont.setPixelSize(this->height() / 2.0); - titlefont.setPixelSize(this->height() / 4.0); + valuefont.setPixelSize(this->height()); + titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + //spacerItem->setGeometry(QRect(0,0,20,this->height()/10.0)); + + QFontMetrics metrics(valuefont); + //valuefont.setPixelSize(this->height() / 2.0); + bool fit = false; + while (!fit) + { + + QFontMetrics valfm( valuefont ); + QRect valbound = valfm.boundingRect(0,0, valueLabel->width(), valueLabel->height(), Qt::TextWordWrap | Qt::AlignLeft, valueLabel->text()); + //QFontMetrics titlefm( titlefont ); + //QRect titlebound = titlefm.boundingRect(0,0, titleLabel->width(), titleLabel->height(), Qt::TextWordWrap | Qt::AlignLeft, titleLabel->text()); + + if ((valbound.width() <= valueLabel->width() && valbound.height() <= valueLabel->height()))// && (titlebound.width() <= titleLabel->width() && titlebound.height() <= titleLabel->height())) + fit = true; + else + { + if (valuefont.pixelSize()-5 <= 0) + { + fit = true; + valuefont.setPixelSize(5); + } + else + { + valuefont.setPixelSize(valuefont.pixelSize() - 5); + } + //titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + //qDebug() << "Point size:" << valuefont.pixelSize() << valueLabel->width() << valueLabel->height(); + } + } +titlefont.setPixelSize(valuefont.pixelSize() / 2.0); valueLabel->setFont(valuefont); titleLabel->setFont(titlefont); update(); diff --git a/src/ui/uas/UASQuickViewTextItem.h b/src/ui/uas/UASQuickViewTextItem.h index ba3eb8193c3363c2f382168f2f7f781c3ee3ce20..dea8cc3b16fb0f2773376038e95c0d6baf615d55 100644 --- a/src/ui/uas/UASQuickViewTextItem.h +++ b/src/ui/uas/UASQuickViewTextItem.h @@ -3,6 +3,7 @@ #include "UASQuickViewItem.h" #include +#include class UASQuickViewTextItem : public UASQuickViewItem { public: @@ -14,6 +15,7 @@ protected: private: QLabel *titleLabel; QLabel *valueLabel; + QSpacerItem *spacerItem; }; #endif // UASQUICKVIEWTEXTITEM_H