|
@@ -0,0 +1,1013 @@
|
|
|
+/****************************************************************************
|
|
|
+** Copyright (c) 2000-2003 Wayne Roth
|
|
|
+** Copyright (c) 2004-2007 Stefan Sander
|
|
|
+** Copyright (c) 2007 Michal Policht
|
|
|
+** Copyright (c) 2008 Brandon Fosdick
|
|
|
+** Copyright (c) 2009-2010 Liam Staskawicz
|
|
|
+** Copyright (c) 2011 Debao Zhang
|
|
|
+** All right reserved.
|
|
|
+** Web: http://code.google.com/p/qextserialport/
|
|
|
+**
|
|
|
+** Permission is hereby granted, free of charge, to any person obtaining
|
|
|
+** a copy of this software and associated documentation files (the
|
|
|
+** "Software"), to deal in the Software without restriction, including
|
|
|
+** without limitation the rights to use, copy, modify, merge, publish,
|
|
|
+** distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
+** permit persons to whom the Software is furnished to do so, subject to
|
|
|
+** the following conditions:
|
|
|
+**
|
|
|
+** The above copyright notice and this permission notice shall be
|
|
|
+** included in all copies or substantial portions of the Software.
|
|
|
+**
|
|
|
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
+**
|
|
|
+****************************************************************************/
|
|
|
+
|
|
|
+#include "qextserialport.h"
|
|
|
+#include "qextserialport_p.h"
|
|
|
+#include <stdio.h>
|
|
|
+#include <QtCore/QDebug>
|
|
|
+#include <QtCore/QReadLocker>
|
|
|
+#include <QtCore/QWriteLocker>
|
|
|
+
|
|
|
+/*!
|
|
|
+ \class PortSettings
|
|
|
+
|
|
|
+ \brief The PortSettings class contain port settings
|
|
|
+
|
|
|
+ Structure to contain port settings.
|
|
|
+
|
|
|
+ \code
|
|
|
+ BaudRateType BaudRate;
|
|
|
+ DataBitsType DataBits;
|
|
|
+ ParityType Parity;
|
|
|
+ StopBitsType StopBits;
|
|
|
+ FlowType FlowControl;
|
|
|
+ long Timeout_Millisec;
|
|
|
+ \endcode
|
|
|
+*/
|
|
|
+
|
|
|
+QextSerialPortPrivate::QextSerialPortPrivate(QextSerialPort *q)
|
|
|
+ :lock(QReadWriteLock::Recursive), q_ptr(q)
|
|
|
+{
|
|
|
+ lastErr = E_NO_ERROR;
|
|
|
+ settings.BaudRate = BAUD9600;
|
|
|
+ settings.Parity = PAR_NONE;
|
|
|
+ settings.FlowControl = FLOW_OFF;
|
|
|
+ settings.DataBits = DATA_8;
|
|
|
+ settings.StopBits = STOP_1;
|
|
|
+ settings.Timeout_Millisec = 10;
|
|
|
+ settingsDirtyFlags = DFE_ALL;
|
|
|
+
|
|
|
+ platformSpecificInit();
|
|
|
+}
|
|
|
+
|
|
|
+QextSerialPortPrivate::~QextSerialPortPrivate()
|
|
|
+{
|
|
|
+ platformSpecificDestruct();
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setBaudRate(BaudRateType baudRate, bool update)
|
|
|
+{
|
|
|
+ switch (baudRate) {
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ //Windows Special
|
|
|
+ case BAUD14400:
|
|
|
+ case BAUD56000:
|
|
|
+ case BAUD128000:
|
|
|
+ case BAUD256000:
|
|
|
+ QESP_PORTABILITY_WARNING()<<"QextSerialPort Portability Warning: POSIX does not support baudRate:"<<baudRate;
|
|
|
+#elif defined(Q_OS_UNIX)
|
|
|
+ //Unix Special
|
|
|
+ case BAUD50:
|
|
|
+ case BAUD75:
|
|
|
+ case BAUD134:
|
|
|
+ case BAUD150:
|
|
|
+ case BAUD200:
|
|
|
+ case BAUD1800:
|
|
|
+# ifdef B76800
|
|
|
+ case BAUD76800:
|
|
|
+# endif
|
|
|
+# if defined(B230400) && defined(B4000000)
|
|
|
+ case BAUD230400:
|
|
|
+ case BAUD460800:
|
|
|
+ case BAUD500000:
|
|
|
+ case BAUD576000:
|
|
|
+ case BAUD921600:
|
|
|
+ case BAUD1000000:
|
|
|
+ case BAUD1152000:
|
|
|
+ case BAUD1500000:
|
|
|
+ case BAUD2000000:
|
|
|
+ case BAUD2500000:
|
|
|
+ case BAUD3000000:
|
|
|
+ case BAUD3500000:
|
|
|
+ case BAUD4000000:
|
|
|
+# endif
|
|
|
+ QESP_PORTABILITY_WARNING()<<"QextSerialPort Portability Warning: Windows does not support baudRate:"<<baudRate;
|
|
|
+#endif
|
|
|
+ case BAUD110:
|
|
|
+ case BAUD300:
|
|
|
+ case BAUD600:
|
|
|
+ case BAUD1200:
|
|
|
+ case BAUD2400:
|
|
|
+ case BAUD4800:
|
|
|
+ case BAUD9600:
|
|
|
+ case BAUD19200:
|
|
|
+ case BAUD38400:
|
|
|
+ case BAUD57600:
|
|
|
+ case BAUD115200:
|
|
|
+#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
|
|
+ default:
|
|
|
+#endif
|
|
|
+ settings.BaudRate = baudRate;
|
|
|
+ settingsDirtyFlags |= DFE_BaudRate;
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+ break;
|
|
|
+#if !(defined(Q_OS_WIN) || defined(Q_OS_MAC))
|
|
|
+ default:
|
|
|
+ QESP_WARNING()<<"QextSerialPort does not support baudRate:"<<baudRate;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setParity(ParityType parity, bool update)
|
|
|
+{
|
|
|
+ switch (parity) {
|
|
|
+ case PAR_SPACE:
|
|
|
+ if (settings.DataBits == DATA_8) {
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: Space parity with 8 data bits is not supported by POSIX systems.");
|
|
|
+#else
|
|
|
+ QESP_WARNING("Space parity with 8 data bits is not supported by POSIX systems.");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ /*mark parity - WINDOWS ONLY*/
|
|
|
+ case PAR_MARK:
|
|
|
+ QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: Mark parity is not supported by POSIX systems");
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+
|
|
|
+ case PAR_NONE:
|
|
|
+ case PAR_EVEN:
|
|
|
+ case PAR_ODD:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ QESP_WARNING()<<"QextSerialPort does not support Parity:" << parity;
|
|
|
+ }
|
|
|
+
|
|
|
+ settings.Parity = parity;
|
|
|
+ settingsDirtyFlags |= DFE_Parity;
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setDataBits(DataBitsType dataBits, bool update)
|
|
|
+{
|
|
|
+ switch(dataBits) {
|
|
|
+
|
|
|
+ case DATA_5:
|
|
|
+ if (settings.StopBits == STOP_2) {
|
|
|
+ QESP_WARNING("QextSerialPort: 5 Data bits cannot be used with 2 stop bits.");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ settings.DataBits = dataBits;
|
|
|
+ settingsDirtyFlags |= DFE_DataBits;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DATA_6:
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ if (settings.StopBits == STOP_1_5) {
|
|
|
+ QESP_WARNING("QextSerialPort: 6 Data bits cannot be used with 1.5 stop bits.");
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ settings.DataBits = dataBits;
|
|
|
+ settingsDirtyFlags |= DFE_DataBits;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DATA_7:
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ if (settings.StopBits == STOP_1_5) {
|
|
|
+ QESP_WARNING("QextSerialPort: 7 Data bits cannot be used with 1.5 stop bits.");
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ settings.DataBits = dataBits;
|
|
|
+ settingsDirtyFlags |= DFE_DataBits;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DATA_8:
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ if (settings.StopBits == STOP_1_5) {
|
|
|
+ QESP_WARNING("QextSerialPort: 8 Data bits cannot be used with 1.5 stop bits.");
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ settings.DataBits = dataBits;
|
|
|
+ settingsDirtyFlags |= DFE_DataBits;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ QESP_WARNING()<<"QextSerialPort does not support Data bits:"<<dataBits;
|
|
|
+ }
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setStopBits(StopBitsType stopBits, bool update)
|
|
|
+{
|
|
|
+ switch (stopBits) {
|
|
|
+
|
|
|
+ /*one stop bit*/
|
|
|
+ case STOP_1:
|
|
|
+ settings.StopBits = stopBits;
|
|
|
+ settingsDirtyFlags |= DFE_StopBits;
|
|
|
+ break;
|
|
|
+
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ /*1.5 stop bits*/
|
|
|
+ case STOP_1_5:
|
|
|
+ QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: 1.5 stop bit operation is not supported by POSIX.");
|
|
|
+ if (settings.DataBits != DATA_5) {
|
|
|
+ QESP_WARNING("QextSerialPort: 1.5 stop bits can only be used with 5 data bits");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ settings.StopBits = stopBits;
|
|
|
+ settingsDirtyFlags |= DFE_StopBits;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /*two stop bits*/
|
|
|
+ case STOP_2:
|
|
|
+ if (settings.DataBits == DATA_5) {
|
|
|
+ QESP_WARNING("QextSerialPort: 2 stop bits cannot be used with 5 data bits");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ settings.StopBits = stopBits;
|
|
|
+ settingsDirtyFlags |= DFE_StopBits;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ QESP_WARNING()<<"QextSerialPort does not support stop bits: "<<stopBits;
|
|
|
+ }
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setFlowControl(FlowType flow, bool update)
|
|
|
+{
|
|
|
+ settings.FlowControl = flow;
|
|
|
+ settingsDirtyFlags |= DFE_Flow;
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setTimeout(long millisec, bool update)
|
|
|
+{
|
|
|
+ settings.Timeout_Millisec = millisec;
|
|
|
+ settingsDirtyFlags |= DFE_TimeOut;
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+}
|
|
|
+
|
|
|
+void QextSerialPortPrivate::setPortSettings(const PortSettings &settings, bool update)
|
|
|
+{
|
|
|
+ setBaudRate(settings.BaudRate, false);
|
|
|
+ setDataBits(settings.DataBits, false);
|
|
|
+ setStopBits(settings.StopBits, false);
|
|
|
+ setParity(settings.Parity, false);
|
|
|
+ setFlowControl(settings.FlowControl, false);
|
|
|
+ setTimeout(settings.Timeout_Millisec, false);
|
|
|
+ settingsDirtyFlags = DFE_ALL;
|
|
|
+ if (update && q_func()->isOpen())
|
|
|
+ updatePortSettings();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void QextSerialPortPrivate::_q_canRead()
|
|
|
+{
|
|
|
+ qint64 maxSize = bytesAvailable_sys();
|
|
|
+ if (maxSize > 0) {
|
|
|
+ char *writePtr = readBuffer.reserve(size_t(maxSize));
|
|
|
+ qint64 bytesRead = readData_sys(writePtr, maxSize);
|
|
|
+ if (bytesRead < maxSize)
|
|
|
+ readBuffer.chop(maxSize - bytesRead);
|
|
|
+ Q_Q(QextSerialPort);
|
|
|
+ Q_EMIT q->readyRead();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*! \class QextSerialPort
|
|
|
+
|
|
|
+ \brief The QextSerialPort class encapsulates a serial port on both POSIX and Windows systems.
|
|
|
+
|
|
|
+ \section1 Usage
|
|
|
+ QextSerialPort offers both a polling and event driven API. Event driven
|
|
|
+ is typically easier to use, since you never have to worry about checking
|
|
|
+ for new data.
|
|
|
+
|
|
|
+ \bold Example
|
|
|
+ \code
|
|
|
+ QextSerialPort *port = new QextSerialPort("COM1");
|
|
|
+ connect(port, SIGNAL(readyRead()), myClass, SLOT(onDataAvailable()));
|
|
|
+ port->open();
|
|
|
+
|
|
|
+ void MyClass::onDataAvailable()
|
|
|
+ {
|
|
|
+ QByteArray data = port->readAll();
|
|
|
+ processNewData(usbdata);
|
|
|
+ }
|
|
|
+ \endcode
|
|
|
+
|
|
|
+ \section1 Compatibility
|
|
|
+ The user will be notified of errors and possible portability conflicts at run-time
|
|
|
+ by default.
|
|
|
+
|
|
|
+ For example, if a application has used BAUD1800, when it is runing under unix, you
|
|
|
+ will get following message.
|
|
|
+
|
|
|
+ \code
|
|
|
+ QextSerialPort Portability Warning: Windows does not support baudRate:1800
|
|
|
+ \endcode
|
|
|
+
|
|
|
+ This behavior can be turned off by defining macro QESP_NO_WARN (to turn off all warnings)
|
|
|
+ or QESP_NO_PORTABILITY_WARN (to turn off portability warnings) in the project.
|
|
|
+
|
|
|
+
|
|
|
+ \bold Author: Stefan Sander, Michal Policht, Brandon Fosdick, Liam Staskawicz, Debao Zhang
|
|
|
+*/
|
|
|
+
|
|
|
+/*!
|
|
|
+ \enum QextSerialPort::QueryMode
|
|
|
+
|
|
|
+ This enum type specifies query mode used in a serial port:
|
|
|
+
|
|
|
+ \value Polling
|
|
|
+ asynchronously read and write
|
|
|
+ \value EventDriven
|
|
|
+ synchronously read and write
|
|
|
+*/
|
|
|
+
|
|
|
+/*!
|
|
|
+ \fn void QextSerialPort::dsrChanged(bool status)
|
|
|
+ This signal is emitted whenever dsr line has changed its state. You may
|
|
|
+ use this signal to check if device is connected.
|
|
|
+
|
|
|
+ \a status true when DSR signal is on, false otherwise.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+/*!
|
|
|
+ \fn QueryMode QextSerialPort::queryMode() const
|
|
|
+ Get query mode.
|
|
|
+ */
|
|
|
+
|
|
|
+/*!
|
|
|
+ Default constructor. Note that the name of the device used by a QextSerialPort is dependent on
|
|
|
+ your OS. Possible naming conventions and their associated OS are:
|
|
|
+
|
|
|
+ \code
|
|
|
+
|
|
|
+ OS Constant Used By Naming Convention
|
|
|
+ ------------- ------------- ------------------------
|
|
|
+ Q_OS_WIN Windows COM1, COM2
|
|
|
+ Q_OS_IRIX SGI/IRIX /dev/ttyf1, /dev/ttyf2
|
|
|
+ Q_OS_HPUX HP-UX /dev/tty1p0, /dev/tty2p0
|
|
|
+ Q_OS_SOLARIS SunOS/Slaris /dev/ttya, /dev/ttyb
|
|
|
+ Q_OS_OSF Digital UNIX /dev/tty01, /dev/tty02
|
|
|
+ Q_OS_FREEBSD FreeBSD /dev/ttyd0, /dev/ttyd1
|
|
|
+ Q_OS_OPENBSD OpenBSD /dev/tty00, /dev/tty01
|
|
|
+ Q_OS_LINUX Linux /dev/ttyS0, /dev/ttyS1
|
|
|
+ <none> /dev/ttyS0, /dev/ttyS1
|
|
|
+ \endcode
|
|
|
+
|
|
|
+ This constructor assigns the device name to the name of the first port on the specified system.
|
|
|
+ See the other constructors if you need to open a different port. Default \a mode is EventDriven.
|
|
|
+ As a subclass of QObject, \a parent can be specified.
|
|
|
+*/
|
|
|
+
|
|
|
+QextSerialPort::QextSerialPort(QextSerialPort::QueryMode mode, QObject *parent)
|
|
|
+ : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this))
|
|
|
+{
|
|
|
+#ifdef Q_OS_WIN
|
|
|
+ setPortName(QLatin1String("COM1"));
|
|
|
+
|
|
|
+#elif defined(Q_OS_IRIX)
|
|
|
+ setPortName(QLatin1String("/dev/ttyf1"));
|
|
|
+
|
|
|
+#elif defined(Q_OS_HPUX)
|
|
|
+ setPortName(QLatin1String("/dev/tty1p0"));
|
|
|
+
|
|
|
+#elif defined(Q_OS_SOLARIS)
|
|
|
+ setPortName(QLatin1String("/dev/ttya"));
|
|
|
+
|
|
|
+#elif defined(Q_OS_OSF) //formally DIGITAL UNIX
|
|
|
+ setPortName(QLatin1String("/dev/tty01"));
|
|
|
+
|
|
|
+#elif defined(Q_OS_FREEBSD)
|
|
|
+ setPortName(QLatin1String("/dev/ttyd1"));
|
|
|
+
|
|
|
+#elif defined(Q_OS_OPENBSD)
|
|
|
+ setPortName(QLatin1String("/dev/tty00"));
|
|
|
+
|
|
|
+#else
|
|
|
+ setPortName(QLatin1String("/dev/ttyS0"));
|
|
|
+#endif
|
|
|
+ setQueryMode(mode);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Constructs a serial port attached to the port specified by name.
|
|
|
+ \a name is the name of the device, which is windowsystem-specific,
|
|
|
+ e.g."COM1" or "/dev/ttyS0". \a mode
|
|
|
+*/
|
|
|
+QextSerialPort::QextSerialPort(const QString &name, QextSerialPort::QueryMode mode, QObject *parent)
|
|
|
+ : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this))
|
|
|
+{
|
|
|
+ setQueryMode(mode);
|
|
|
+ setPortName(name);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Constructs a port with default name and specified \a settings.
|
|
|
+*/
|
|
|
+QextSerialPort::QextSerialPort(const PortSettings &settings, QextSerialPort::QueryMode mode, QObject *parent)
|
|
|
+ : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this))
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ setQueryMode(mode);
|
|
|
+ d->setPortSettings(settings);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Constructs a port with specified \a name , \a mode and \a settings.
|
|
|
+*/
|
|
|
+QextSerialPort::QextSerialPort(const QString &name, const PortSettings &settings, QextSerialPort::QueryMode mode, QObject *parent)
|
|
|
+ : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this))
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ setPortName(name);
|
|
|
+ setQueryMode(mode);
|
|
|
+ d->setPortSettings(settings);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Opens a serial port and sets its OpenMode to \a mode.
|
|
|
+ Note that this function does not specify which device to open.
|
|
|
+ Returns true if successful; otherwise returns false.This function has no effect
|
|
|
+ if the port associated with the class is already open. The port is also
|
|
|
+ configured to the current settings, as stored in the settings structure.
|
|
|
+*/
|
|
|
+bool QextSerialPort::open(OpenMode mode)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (mode != QIODevice::NotOpen && !isOpen())
|
|
|
+ d->open_sys(mode);
|
|
|
+
|
|
|
+ return isOpen();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*! \reimp
|
|
|
+ Closes a serial port. This function has no effect if the serial port associated with the class
|
|
|
+ is not currently open.
|
|
|
+*/
|
|
|
+void QextSerialPort::close()
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (isOpen()) {
|
|
|
+ // Be a good QIODevice and call QIODevice::close() before really close()
|
|
|
+ // so the aboutToClose() signal is emitted at the proper time
|
|
|
+ QIODevice::close(); // mark ourselves as closed
|
|
|
+ d->close_sys();
|
|
|
+ d->readBuffer.clear();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Flushes all pending I/O to the serial port. This function has no effect if the serial port
|
|
|
+ associated with the class is not currently open.
|
|
|
+*/
|
|
|
+void QextSerialPort::flush()
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (isOpen())
|
|
|
+ d->flush_sys();
|
|
|
+}
|
|
|
+
|
|
|
+/*! \reimp
|
|
|
+ Returns the number of bytes waiting in the port's receive queue. This function will return 0 if
|
|
|
+ the port is not currently open, or -1 on error.
|
|
|
+*/
|
|
|
+qint64 QextSerialPort::bytesAvailable() const
|
|
|
+{
|
|
|
+ QWriteLocker locker(&d_func()->lock);
|
|
|
+ if (isOpen()) {
|
|
|
+ qint64 bytes = d_func()->bytesAvailable_sys();
|
|
|
+ if (bytes != -1) {
|
|
|
+ return bytes + d_func()->readBuffer.size()
|
|
|
+ + QIODevice::bytesAvailable();
|
|
|
+ } else {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*! \reimp
|
|
|
+
|
|
|
+*/
|
|
|
+bool QextSerialPort::canReadLine() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return QIODevice::canReadLine() || d_func()->readBuffer.canReadLine();
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ * Set desired serial communication handling style. You may choose from polling
|
|
|
+ * or event driven approach. This function does nothing when port is open; to
|
|
|
+ * apply changes port must be reopened.
|
|
|
+ *
|
|
|
+ * In event driven approach read() and write() functions are acting
|
|
|
+ * asynchronously. They return immediately and the operation is performed in
|
|
|
+ * the background, so they doesn't freeze the calling thread.
|
|
|
+ * To determine when operation is finished, QextSerialPort runs separate thread
|
|
|
+ * and monitors serial port events. Whenever the event occurs, adequate signal
|
|
|
+ * is emitted.
|
|
|
+ *
|
|
|
+ * When polling is set, read() and write() are acting synchronously. Signals are
|
|
|
+ * not working in this mode and some functions may not be available. The advantage
|
|
|
+ * of polling is that it generates less overhead due to lack of signals emissions
|
|
|
+ * and it doesn't start separate thread to monitor events.
|
|
|
+ *
|
|
|
+ * Generally event driven approach is more capable and friendly, although some
|
|
|
+ * applications may need as low overhead as possible and then polling comes.
|
|
|
+ *
|
|
|
+ * \a mode query mode.
|
|
|
+ */
|
|
|
+void QextSerialPort::setQueryMode(QueryMode mode)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (mode != d->queryMode) {
|
|
|
+ d->queryMode = mode;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets the \a name of the device associated with the object, e.g. "COM1", or "/dev/ttyS0".
|
|
|
+*/
|
|
|
+void QextSerialPort::setPortName(const QString &name)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ d->port = name;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the name set by setPortName().
|
|
|
+*/
|
|
|
+QString QextSerialPort::portName() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->port;
|
|
|
+}
|
|
|
+
|
|
|
+QextSerialPort::QueryMode QextSerialPort::queryMode() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->queryMode;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Reads all available data from the device, and returns it as a QByteArray.
|
|
|
+ This function has no way of reporting errors; returning an empty QByteArray()
|
|
|
+ can mean either that no data was currently available for reading, or that an error occurred.
|
|
|
+*/
|
|
|
+QByteArray QextSerialPort::readAll()
|
|
|
+{
|
|
|
+ int avail = this->bytesAvailable();
|
|
|
+ return (avail > 0) ? this->read(avail) : QByteArray();
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the baud rate of the serial port. For a list of possible return values see
|
|
|
+ the definition of the enum BaudRateType.
|
|
|
+*/
|
|
|
+BaudRateType QextSerialPort::baudRate() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->settings.BaudRate;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the number of data bits used by the port. For a list of possible values returned by
|
|
|
+ this function, see the definition of the enum DataBitsType.
|
|
|
+*/
|
|
|
+DataBitsType QextSerialPort::dataBits() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->settings.DataBits;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the type of parity used by the port. For a list of possible values returned by
|
|
|
+ this function, see the definition of the enum ParityType.
|
|
|
+*/
|
|
|
+ParityType QextSerialPort::parity() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->settings.Parity;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the number of stop bits used by the port. For a list of possible return values, see
|
|
|
+ the definition of the enum StopBitsType.
|
|
|
+*/
|
|
|
+StopBitsType QextSerialPort::stopBits() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->settings.StopBits;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the type of flow control used by the port. For a list of possible values returned
|
|
|
+ by this function, see the definition of the enum FlowType.
|
|
|
+*/
|
|
|
+FlowType QextSerialPort::flowControl() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->settings.FlowControl;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ \reimp
|
|
|
+ Returns true if device is sequential, otherwise returns false. Serial port is sequential device
|
|
|
+ so this function always returns true. Check QIODevice::isSequential() documentation for more
|
|
|
+ information.
|
|
|
+*/
|
|
|
+bool QextSerialPort::isSequential() const
|
|
|
+{
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Return the error number, or 0 if no error occurred.
|
|
|
+*/
|
|
|
+ulong QextSerialPort::lastError() const
|
|
|
+{
|
|
|
+ QReadLocker locker(&d_func()->lock);
|
|
|
+ return d_func()->lastErr;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns the line status as stored by the port function. This function will retrieve the states
|
|
|
+ of the following lines: DCD, CTS, DSR, and RI. On POSIX systems, the following additional lines
|
|
|
+ can be monitored: DTR, RTS, Secondary TXD, and Secondary RXD. The value returned is an unsigned
|
|
|
+ long with specific bits indicating which lines are high. The following constants should be used
|
|
|
+ to examine the states of individual lines:
|
|
|
+
|
|
|
+ \code
|
|
|
+ Mask Line
|
|
|
+ ------ ----
|
|
|
+ LS_CTS CTS
|
|
|
+ LS_DSR DSR
|
|
|
+ LS_DCD DCD
|
|
|
+ LS_RI RI
|
|
|
+ LS_RTS RTS (POSIX only)
|
|
|
+ LS_DTR DTR (POSIX only)
|
|
|
+ LS_ST Secondary TXD (POSIX only)
|
|
|
+ LS_SR Secondary RXD (POSIX only)
|
|
|
+ \endcode
|
|
|
+
|
|
|
+ This function will return 0 if the port associated with the class is not currently open.
|
|
|
+*/
|
|
|
+unsigned long QextSerialPort::lineStatus()
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (isOpen())
|
|
|
+ return d->lineStatus_sys();
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Returns a human-readable description of the last device error that occurred.
|
|
|
+*/
|
|
|
+QString QextSerialPort::errorString()
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QReadLocker locker(&d->lock);
|
|
|
+ switch(d->lastErr) {
|
|
|
+ case E_NO_ERROR:
|
|
|
+ return tr("No Error has occurred");
|
|
|
+ case E_INVALID_FD:
|
|
|
+ return tr("Invalid file descriptor (port was not opened correctly)");
|
|
|
+ case E_NO_MEMORY:
|
|
|
+ return tr("Unable to allocate memory tables (POSIX)");
|
|
|
+ case E_CAUGHT_NON_BLOCKED_SIGNAL:
|
|
|
+ return tr("Caught a non-blocked signal (POSIX)");
|
|
|
+ case E_PORT_TIMEOUT:
|
|
|
+ return tr("Operation timed out (POSIX)");
|
|
|
+ case E_INVALID_DEVICE:
|
|
|
+ return tr("The file opened by the port is not a valid device");
|
|
|
+ case E_BREAK_CONDITION:
|
|
|
+ return tr("The port detected a break condition");
|
|
|
+ case E_FRAMING_ERROR:
|
|
|
+ return tr("The port detected a framing error (usually caused by incorrect baud rate settings)");
|
|
|
+ case E_IO_ERROR:
|
|
|
+ return tr("There was an I/O error while communicating with the port");
|
|
|
+ case E_BUFFER_OVERRUN:
|
|
|
+ return tr("Character buffer overrun");
|
|
|
+ case E_RECEIVE_OVERFLOW:
|
|
|
+ return tr("Receive buffer overflow");
|
|
|
+ case E_RECEIVE_PARITY_ERROR:
|
|
|
+ return tr("The port detected a parity error in the received data");
|
|
|
+ case E_TRANSMIT_OVERFLOW:
|
|
|
+ return tr("Transmit buffer overflow");
|
|
|
+ case E_READ_FAILED:
|
|
|
+ return tr("General read operation failure");
|
|
|
+ case E_WRITE_FAILED:
|
|
|
+ return tr("General write operation failure");
|
|
|
+ case E_FILE_NOT_FOUND:
|
|
|
+ return tr("The %1 file doesn't exists").arg(this->portName());
|
|
|
+ case E_PERMISSION_DENIED:
|
|
|
+ return tr("Permission denied");
|
|
|
+ case E_AGAIN:
|
|
|
+ return tr("Device is already locked");
|
|
|
+ case E_OS_SPECIFIC:
|
|
|
+ return tr("OS error: %1").arg(d->lastOSErrString);
|
|
|
+ default:
|
|
|
+ return tr("Unknown error: %1").arg(d->lastErr);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Destructs the QextSerialPort object.
|
|
|
+*/
|
|
|
+QextSerialPort::~QextSerialPort()
|
|
|
+{
|
|
|
+ if (isOpen()) {
|
|
|
+ close();
|
|
|
+ }
|
|
|
+ delete d_ptr;
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets the flow control used by the port to \a flow. Possible values of flow are:
|
|
|
+ \code
|
|
|
+ FLOW_OFF No flow control
|
|
|
+ FLOW_HARDWARE Hardware (RTS/CTS) flow control
|
|
|
+ FLOW_XONXOFF Software (XON/XOFF) flow control
|
|
|
+ \endcode
|
|
|
+*/
|
|
|
+void QextSerialPort::setFlowControl(FlowType flow)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (d->settings.FlowControl != flow)
|
|
|
+ d->setFlowControl(flow, true);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets the parity associated with the serial port to \a parity. The possible values of parity are:
|
|
|
+ \code
|
|
|
+ PAR_SPACE Space Parity
|
|
|
+ PAR_MARK Mark Parity
|
|
|
+ PAR_NONE No Parity
|
|
|
+ PAR_EVEN Even Parity
|
|
|
+ PAR_ODD Odd Parity
|
|
|
+ \endcode
|
|
|
+*/
|
|
|
+void QextSerialPort::setParity(ParityType parity)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (d->settings.Parity != parity)
|
|
|
+ d->setParity(parity, true);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets the number of data bits used by the serial port to \a dataBits. Possible values of dataBits are:
|
|
|
+ \code
|
|
|
+ DATA_5 5 data bits
|
|
|
+ DATA_6 6 data bits
|
|
|
+ DATA_7 7 data bits
|
|
|
+ DATA_8 8 data bits
|
|
|
+ \endcode
|
|
|
+
|
|
|
+ \bold note:
|
|
|
+ This function is subject to the following restrictions:
|
|
|
+ \list
|
|
|
+ \o 5 data bits cannot be used with 2 stop bits.
|
|
|
+ \o 1.5 stop bits can only be used with 5 data bits.
|
|
|
+ \o 8 data bits cannot be used with space parity on POSIX systems.
|
|
|
+ \endlist
|
|
|
+ */
|
|
|
+void QextSerialPort::setDataBits(DataBitsType dataBits)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (d->settings.DataBits != dataBits)
|
|
|
+ d->setDataBits(dataBits, true);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets the number of stop bits used by the serial port to \a stopBits. Possible values of stopBits are:
|
|
|
+ \code
|
|
|
+ STOP_1 1 stop bit
|
|
|
+ STOP_1_5 1.5 stop bits
|
|
|
+ STOP_2 2 stop bits
|
|
|
+ \endcode
|
|
|
+
|
|
|
+ \bold note:
|
|
|
+ This function is subject to the following restrictions:
|
|
|
+ \list
|
|
|
+ \o 2 stop bits cannot be used with 5 data bits.
|
|
|
+ \o 1.5 stop bits cannot be used with 6 or more data bits.
|
|
|
+ \o POSIX does not support 1.5 stop bits.
|
|
|
+ \endlist
|
|
|
+*/
|
|
|
+void QextSerialPort::setStopBits(StopBitsType stopBits)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (d->settings.StopBits != stopBits)
|
|
|
+ d->setStopBits(stopBits, true);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets the baud rate of the serial port to \a baudRate. Note that not all rates are applicable on
|
|
|
+ all platforms. The following table shows translations of the various baud rate
|
|
|
+ constants on Windows(including NT/2000) and POSIX platforms. Speeds marked with an *
|
|
|
+ are speeds that are usable on both Windows and POSIX.
|
|
|
+ \code
|
|
|
+
|
|
|
+ RATE Windows Speed POSIX Speed
|
|
|
+ ----------- ------------- -----------
|
|
|
+ BAUD50 X 50
|
|
|
+ BAUD75 X 75
|
|
|
+ *BAUD110 110 110
|
|
|
+ BAUD134 X 134.5
|
|
|
+ BAUD150 X 150
|
|
|
+ BAUD200 X 200
|
|
|
+ *BAUD300 300 300
|
|
|
+ *BAUD600 600 600
|
|
|
+ *BAUD1200 1200 1200
|
|
|
+ BAUD1800 X 1800
|
|
|
+ *BAUD2400 2400 2400
|
|
|
+ *BAUD4800 4800 4800
|
|
|
+ *BAUD9600 9600 9600
|
|
|
+ BAUD14400 14400 X
|
|
|
+ *BAUD19200 19200 19200
|
|
|
+ *BAUD38400 38400 38400
|
|
|
+ BAUD56000 56000 X
|
|
|
+ *BAUD57600 57600 57600
|
|
|
+ BAUD76800 X 76800
|
|
|
+ *BAUD115200 115200 115200
|
|
|
+ BAUD128000 128000 X
|
|
|
+ BAUD230400 X 230400
|
|
|
+ BAUD256000 256000 X
|
|
|
+ BAUD460800 X 460800
|
|
|
+ BAUD500000 X 500000
|
|
|
+ BAUD576000 X 576000
|
|
|
+ BAUD921600 X 921600
|
|
|
+ BAUD1000000 X 1000000
|
|
|
+ BAUD1152000 X 1152000
|
|
|
+ BAUD1500000 X 1500000
|
|
|
+ BAUD2000000 X 2000000
|
|
|
+ BAUD2500000 X 2500000
|
|
|
+ BAUD3000000 X 3000000
|
|
|
+ BAUD3500000 X 3500000
|
|
|
+ BAUD4000000 X 4000000
|
|
|
+ \endcode
|
|
|
+*/
|
|
|
+
|
|
|
+void QextSerialPort::setBaudRate(BaudRateType baudRate)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (d->settings.BaudRate != baudRate)
|
|
|
+ d->setBaudRate(baudRate, true);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ For Unix:
|
|
|
+
|
|
|
+ Sets the read and write timeouts for the port to \a millisec milliseconds.
|
|
|
+ Note that this is a per-character timeout, i.e. the port will wait this long for each
|
|
|
+ individual character, not for the whole read operation. This timeout also applies to the
|
|
|
+ bytesWaiting() function.
|
|
|
+
|
|
|
+ \bold note:
|
|
|
+ POSIX does not support millisecond-level control for I/O timeout values. Any
|
|
|
+ timeout set using this function will be set to the next lowest tenth of a second for
|
|
|
+ the purposes of detecting read or write timeouts. For example a timeout of 550 milliseconds
|
|
|
+ will be seen by the class as a timeout of 500 milliseconds for the purposes of reading and
|
|
|
+ writing the port. However millisecond-level control is allowed by the select() system call,
|
|
|
+ so for example a 550-millisecond timeout will be seen as 550 milliseconds on POSIX systems for
|
|
|
+ the purpose of detecting available bytes in the read buffer.
|
|
|
+
|
|
|
+ For Windows:
|
|
|
+
|
|
|
+ Sets the read and write timeouts for the port to \a millisec milliseconds.
|
|
|
+ Setting 0 indicates that timeouts are not used for read nor write operations;
|
|
|
+ however read() and write() functions will still block. Set -1 to provide
|
|
|
+ non-blocking behaviour (read() and write() will return immediately).
|
|
|
+
|
|
|
+ \bold note: this function does nothing in event driven mode.
|
|
|
+*/
|
|
|
+void QextSerialPort::setTimeout(long millisec)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (d->settings.Timeout_Millisec != millisec)
|
|
|
+ d->setTimeout(millisec, true);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets DTR line to the requested state (\a set default to high). This function will have no effect if
|
|
|
+ the port associated with the class is not currently open.
|
|
|
+*/
|
|
|
+void QextSerialPort::setDtr(bool set)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (isOpen())
|
|
|
+ d->setDtr_sys(set);
|
|
|
+}
|
|
|
+
|
|
|
+/*!
|
|
|
+ Sets RTS line to the requested state \a set (high by default).
|
|
|
+ This function will have no effect if
|
|
|
+ the port associated with the class is not currently open.
|
|
|
+*/
|
|
|
+void QextSerialPort::setRts(bool set)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ if (isOpen())
|
|
|
+ d->setRts_sys(set);
|
|
|
+}
|
|
|
+
|
|
|
+/*! \reimp
|
|
|
+ Reads a block of data from the serial port. This function will read at most maxlen bytes from
|
|
|
+ the serial port and place them in the buffer pointed to by data. Return value is the number of
|
|
|
+ bytes actually read, or -1 on error.
|
|
|
+
|
|
|
+ \warning before calling this function ensure that serial port associated with this class
|
|
|
+ is currently open (use isOpen() function to check if port is open).
|
|
|
+*/
|
|
|
+qint64 QextSerialPort::readData(char *data, qint64 maxSize)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ qint64 bytesFromBuffer = 0;
|
|
|
+ if (!d->readBuffer.isEmpty()) {
|
|
|
+ bytesFromBuffer = d->readBuffer.read(data, maxSize);
|
|
|
+ if (bytesFromBuffer == maxSize)
|
|
|
+ return bytesFromBuffer;
|
|
|
+ }
|
|
|
+ qint64 bytesFromDevice = d->readData_sys(data+bytesFromBuffer, maxSize-bytesFromBuffer);
|
|
|
+ if (bytesFromDevice < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return bytesFromBuffer + bytesFromDevice;
|
|
|
+}
|
|
|
+
|
|
|
+/*! \reimp
|
|
|
+ Writes a block of data to the serial port. This function will write len bytes
|
|
|
+ from the buffer pointed to by data to the serial port. Return value is the number
|
|
|
+ of bytes actually written, or -1 on error.
|
|
|
+
|
|
|
+ \warning before calling this function ensure that serial port associated with this class
|
|
|
+ is currently open (use isOpen() function to check if port is open).
|
|
|
+*/
|
|
|
+qint64 QextSerialPort::writeData(const char *data, qint64 maxSize)
|
|
|
+{
|
|
|
+ Q_D(QextSerialPort);
|
|
|
+ QWriteLocker locker(&d->lock);
|
|
|
+ return d->writeData_sys(data, maxSize);
|
|
|
+}
|
|
|
+
|
|
|
+#include "moc_qextserialport.cpp"
|