/*
* Unofficial Qt Serial Port Library
*
* Copyright (c) 2010 Inbiza Systems Inc. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program 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 Lesser General Public License
* along with this program. If not, see
*
* author labs@inbiza.com
*/
#include
#include "qserialport.h"
#ifdef TNX_POSIX_SERIAL_PORT
# include
# include
# include
# include
# include "../posix/termioshelper.h"
#elif defined(TNX_WINDOWS_SERIAL_PORT)
# include "win32/commdcbhelper.h"
# include "win32/qwincommevtnotifier.h"
#endif
namespace TNX {
/*!
Constructs a QSerialPort object with the given \a port name and \a parent.
*/
QSerialPort::QSerialPort(const QString &portName, QObject *parent)
: QSerialPortNative(portName, parent), pendingByteCount_(0),
doNotify_(false), readNotifyThreshold_(1)
{
}
/*!
Constructs a QSerialPort object with the given \a port name, \a settings and \a parent.
*/
QSerialPort::QSerialPort(const QString &portName, const QPortSettings &settings, QObject *parent)
: QSerialPortNative(portName, settings, parent), pendingByteCount_(0), doNotify_(false),
readNotifyThreshold_(1)
{
}
/*!
Constructs a QSerialPort object with the given \a port name, \a settings and \a parent.
*/
QSerialPort::QSerialPort(const QString &portName, const QString &settings, QObject *parent)
: QSerialPortNative(portName, settings, parent), pendingByteCount_(0), doNotify_(false),
readNotifyThreshold_(1)
{
}
QSerialPort::~QSerialPort()
{
close();
}
/*!
*/
bool QSerialPort::setPortSettings(const QPortSettings &portSettings)
{
bool result = false;
if ( isOpen() ) {
portHelper_->setBaudRate(portSettings.baudRate());
portHelper_->setDataBits(portSettings.dataBits());
portHelper_->setStopBits(portSettings.stopBits());
portHelper_->setFlowControl(portSettings.flowControl());
portHelper_->setParity(portSettings.parity());
result = portHelper_->applyChanges(PortAttrOnlyAppTy);
}
else {
portSettings_ = portSettings;
result = true;
}
if ( !result )
setErrorString(lastErrorText_impl());
else
portSettings_ = portSettings;
return result;
}
/*! \reimp
*/
bool QSerialPort::isSequential() const
{
return true;
}
/*!
Opens the I/O device for the serial port.
*/
bool QSerialPort::open(OpenMode mode)
{
if ( isOpen() )
return true;
// mode argument is ignored intentionally
if ( portName_.isEmpty() ) {
setErrorString("Port name is empty.");
return false;
}
if ( !open_impl() ) {
qCritical() << QString("QSerialPort::open(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
// we don't know exactly what state this object in before the error.
// make sure that we don't leave any unused object hanging in the memory.
delete portHelper_;
delete readNotifier_;
readNotifier_ = NULL;
portHelper_ = NULL;
return false;
}
// open QIODevice
setOpenMode(mode | QIODevice::Unbuffered);
qDebug() << "Serial port \"" << portName_ << "\" is successfully opened";
// Set port attributes
setPortSettings(portSettings_);
// Set communication timing values
setCommTimeouts(commTimeouts_);
if ( !portHelper_->applyChanges() ) {
qCritical() << QString("QSerialPort::open(%1) failed when setting up the port: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
return true;
}
/*!
Closes the I/O device for the serial port.
See QIODevice::close() for a description of the actions that occur when an I/O
device is closed.
*/
void QSerialPort::close()
{
if ( isOpen() ) {
delete portHelper_;
portHelper_ = NULL;
// disconnect the ReadNotifier
if ( readNotifier_ ) {
disconnect(readNotifier_, SIGNAL(activated(int)), this, SLOT(onDataReceived()));
delete readNotifier_;
readNotifier_ = NULL;
}
close_impl();
// Close the device
QIODevice::close();
qDebug() << "Serial port \"" << portName_ << "\" is successfully closed";
}
}
/*! \reimp
*/
qint64 QSerialPort::pos() const
{
return 0;
}
/*! \reimp
*/
qint64 QSerialPort::size() const
{
return bytesAvailable();
}
/*! \reimp
*/
bool QSerialPort::seek(qint64 /*pos*/)
{
return false;
}
/*! \reimp
*/
bool QSerialPort::atEnd() const
{
return true;
}
/*! \reimp
*/
qint64 QSerialPort::bytesAvailable() const
{
qint64 nBytes = bytesAvailable_impl();
if ( nBytes == -1LL ) {
qDebug() << QString("QSerialPort::bytesAvailable(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
const_cast(this)->setErrorString(lastErrorText_impl());
return -1LL;
}
return QIODevice::bytesAvailable() + nBytes;
}
/*! \reimp
*/
qint64 QSerialPort::bytesToWrite() const
{
return 0LL;
}
/*! \reimp
*/
bool QSerialPort::canReadLine() const
{
return false;
}
/*! \reimp
*/
bool QSerialPort::waitForReadyRead(int timeout)
{
bool ret = false;
readNotifier_->setEnabled(false);
int result = waitForReadyRead_impl((timeout < 0 ? -1 : timeout));
if ( result > 0 ) {
ret = true;
emit readyRead();
}
else if ( result == 0 )
; // Timeout occurred. Do nothing, return false
else {
// Error occurred. Logs the error and return false
qDebug() << QString("QSerialPort::waitForReadyRead(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
readNotifier_->setEnabled(true);
return ret;
}
/*! \reimp
*/
bool QSerialPort::waitForBytesWritten(int /*msecs*/)
{
return true;
}
/*! \reimp
*/
qint64 QSerialPort::readData(char *data, qint64 maxlen)
{
Q_CHECK_PTR(data);
qint64 bytesRead = readData_impl(data, maxlen);
if ( bytesRead == -1LL ) {
qDebug() << QString("QSerialPort::readData(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
if ( bytesRead > 0LL ) {
doNotify_ = false;
// the number of bytes consumed can be higher than the pending byte count
pendingByteCount_ = (pendingByteCount_ - bytesRead) < 0LL ? 0LL :
(pendingByteCount_ - bytesRead);
}
readNotifier_->setEnabled(true);
return bytesRead;
}
/*! \reimp
*/
qint64 QSerialPort::writeData(const char *data, qint64 len)
{
Q_CHECK_PTR(data);
qint64 nBytes = writeData_impl(data, len);
if ( nBytes == -1LL ) {
qDebug() << QString("QSerialPort::writeData(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
if ( 0LL == nBytes && 0LL < len ) {
qDebug() << QString("QSerialPort::writeData(%1) - method returns no error but " \
"number of bytes written is zero: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
}
if ( nBytes > 0LL )
emit bytesWritten(nBytes);
return nBytes;
}
/*!
*/
void QSerialPort::onDataReceived()
{
qint64 nBytes = bytesAvailable_impl();
if ( -1LL == nBytes )
return;
if ( nBytes > pendingByteCount_ ||
(nBytes > 0LL && nBytes == pendingByteCount_ && !doNotify_) ) {
pendingByteCount_ = nBytes;
doNotify_ = true;
if ( pendingByteCount_ >= (qint64)readNotifyThreshold_ ) {
readNotifier_->setEnabled(false);
emit readyRead();
}
}
}
/*!
*/
bool QSerialPort::flushOutBuffer()
{
bool result = flushOutBuffer_impl();
if ( !result ) {
qDebug() << QString("QSerialPort::flushOutBuffer(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
return result;
}
/*!
*/
bool QSerialPort::flushInBuffer()
{
bool result = flushInBuffer_impl();
if ( !result ) {
qDebug() << QString("QSerialPort::flushInBuffer(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
else {
pendingByteCount_ = 0LL;
readNotifier_->setEnabled(true);
}
return result;
}
/*!
*/
bool QSerialPort::sendBreak(int timeout)
{
bool result = sendBreak_impl(timeout);
if ( !result ) {
qDebug() << QString("QSerialPort::sendBreak(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
return result;
}
CommTimeouts QSerialPort::commTimeouts()
{
if ( !isOpen() )
return commTimeouts_;
Q_CHECK_PTR(portHelper_);
CommTimeouts commtimeouts;
bool res = portHelper_->commTimeouts(commtimeouts);
if ( !res ) {
qDebug() << QString("QSerialPort::commTimeouts(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
else {
commTimeouts_ = commtimeouts;
}
return commTimeouts_;
}
bool QSerialPort::setCommTimeouts(const CommTimeouts commtimeouts)
{
commTimeouts_ = commtimeouts;
if ( !isOpen() )
return true;
Q_CHECK_PTR(portHelper_);
portHelper_->setCommTimeouts(commTimeouts_);
bool result = portHelper_->applyChanges(CommTimeoutsOnlyAppTy);
if ( !result ) {
qDebug() << QString("QSerialPort::setCommTimouts(%1) failed: %2(Err #%3)")
.arg(portName_)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
return result;
}
bool QSerialPort::setCommTimeouts(CommTimeoutSchemes scheme, int timeout)
{
if ( scheme == CtScheme_NonBlockingRead ) {
commTimeouts_.PosixVMIN = 0;
commTimeouts_.PosixVTIME = 0;
commTimeouts_.Win32ReadIntervalTimeout = CommTimeouts::NoTimeout;
commTimeouts_.Win32ReadTotalTimeoutConstant = 0;
commTimeouts_.Win32ReadTotalTimeoutMultiplier = 0;
}
else if ( scheme == CtScheme_TimedRead ) {
commTimeouts_.PosixVMIN = 0;
// converting ms to one-tenths-of-second (sec * 0.1)
commTimeouts_.PosixVTIME = timeout / 100;
commTimeouts_.Win32ReadIntervalTimeout = 0;
commTimeouts_.Win32ReadTotalTimeoutConstant = timeout;
commTimeouts_.Win32ReadTotalTimeoutMultiplier = 0;
}
if ( !isOpen() )
return true;
Q_CHECK_PTR(portHelper_);
portHelper_->setCommTimeouts(commTimeouts_);
bool result = portHelper_->applyChanges(CommTimeoutsOnlyAppTy);
if ( !result ) {
qDebug() << QString("QSerialPort::setCommTimouts(%1, scheme: %2) failed: %3(Err #%4)")
.arg(portName_)
.arg((int)scheme)
.arg(lastErrorText_impl())
.arg(lastError_impl());
setErrorString(lastErrorText_impl());
}
return result;
}
/*!
*/
QPortSettings::BaudRate QSerialPort::baudRate() const
{
if ( !isOpen() )
return portSettings_.baudRate();
Q_CHECK_PTR(portHelper_);
return portHelper_->baudRate();
}
/*!
*/
bool QSerialPort::setBaudRate(QPortSettings::BaudRate baudRate)
{
if ( !isOpen() ) {
portSettings_.setBaudRate(baudRate);
return true;
}
Q_CHECK_PTR(portHelper_);
bool result = false;
portHelper_->setBaudRate(baudRate);
if ( (result = portHelper_->applyChanges(PortAttrOnlyAppTy)) )
portSettings_.setBaudRate(baudRate);
else
setErrorString(lastErrorText_impl());
return result;
}
/*!
*/
QPortSettings::Parity QSerialPort::parity() const
{
if ( !isOpen() )
return portSettings_.parity();
Q_CHECK_PTR(portHelper_);
return portHelper_->parity();
}
/*!
*/
bool QSerialPort::setParity(QPortSettings::Parity parity)
{
if ( !isOpen() ) {
portSettings_.setParity(parity);
return true;
}
Q_CHECK_PTR(portHelper_);
bool result = false;
portHelper_->setParity(parity);
if ( (result = portHelper_->applyChanges(PortAttrOnlyAppTy)) )
portSettings_.setParity(parity);
else
setErrorString(lastErrorText_impl());
return result;
}
/*!
*/
QPortSettings::StopBits QSerialPort::stopBits() const
{
if ( !isOpen() )
return portSettings_.stopBits();
Q_CHECK_PTR(portHelper_);
return portHelper_->stopBits();
}
/*!
*/
bool QSerialPort::setStopBits(QPortSettings::StopBits stopBits)
{
if ( !isOpen() ) {
portSettings_.setStopBits(stopBits);
return true;
}
Q_CHECK_PTR(portHelper_);
bool result = false;
portHelper_->setStopBits(stopBits);
if ( (result = portHelper_->applyChanges(PortAttrOnlyAppTy)) )
portSettings_.setStopBits(stopBits);
else
setErrorString(lastErrorText_impl());
return result;
}
/*!
*/
QPortSettings::DataBits QSerialPort::dataBits() const
{
if ( !isOpen() )
return portSettings_.dataBits();
Q_CHECK_PTR(portHelper_);
return portHelper_->dataBits();
}
/*!
*/
bool QSerialPort::setDataBits(QPortSettings::DataBits dataBits)
{
if ( !isOpen() ) {
portSettings_.setDataBits(dataBits);
return true;
}
Q_CHECK_PTR(portHelper_);
bool result = false;
portHelper_->setDataBits(dataBits);
if ( (result = portHelper_->applyChanges(PortAttrOnlyAppTy)) )
portSettings_.setDataBits(dataBits);
else
setErrorString(lastErrorText_impl());
return result;
}
/*!
*/
QPortSettings::FlowControl QSerialPort::flowControl() const
{
if ( !isOpen() )
return portSettings_.flowControl();
Q_CHECK_PTR(portHelper_);
return portHelper_->flowControl();
}
/*!
*/
bool QSerialPort::setFlowControl(QPortSettings::FlowControl flowControl)
{
if ( !isOpen() ) {
portSettings_.setFlowControl(flowControl);
return true;
}
Q_CHECK_PTR(portHelper_);
bool result = false;
portHelper_->setFlowControl(flowControl);
if ( (result = portHelper_->applyChanges(PortAttrOnlyAppTy)) )
portSettings_.setFlowControl(flowControl);
else
setErrorString(lastErrorText_impl());
return result;
}
/*!
*/
bool QSerialPort::setRts(bool on)
{
if ( !isOpen() )
return false;
if ( !portHelper_->setRts(on) ) {
setErrorString(lastErrorText_impl());
return false;
}
return true;
}
/*!
*/
bool QSerialPort::setDtr(bool on)
{
if ( !isOpen() )
return false;
if ( !portHelper_->setDtr(on) ) {
setErrorString(lastErrorText_impl());
return false;
}
return true;
}
/*!
*/
QSerialPort::CommSignalValues QSerialPort::cts()
{
if ( !isOpen() )
return Signal_Unknown;
CommSignalValues cts;
if ( Signal_Unknown == (cts = portHelper_->cts()) )
setErrorString(lastErrorText_impl());
return cts;
}
/*!
*/
QSerialPort::CommSignalValues QSerialPort::dsr()
{
if ( !isOpen() )
return Signal_Unknown;
CommSignalValues dsr;
if ( Signal_Unknown == (dsr = portHelper_->dsr()) )
setErrorString(lastErrorText_impl());
return dsr;
}
/*!
*/
QSerialPort::CommSignalValues QSerialPort::dcd()
{
if ( !isOpen() )
return Signal_Unknown;
CommSignalValues dcd;
if ( Signal_Unknown == (dcd = portHelper_->dcd()) )
setErrorString(lastErrorText_impl());
return dcd;
}
/*!
*/
QSerialPort::CommSignalValues QSerialPort::ri()
{
if ( !isOpen() )
return Signal_Unknown;
CommSignalValues ri;
if ( Signal_Unknown == (ri = portHelper_->ri()) )
setErrorString(lastErrorText_impl());
return ri;
}
} // namespace