4#include <QtCore/QSettings>
5#include <QtCore/QThread>
6#include <QtCore/QTimer>
11 constexpr int CONNECT_TIMEOUT_MS = 1000;
12 constexpr int DISCONNECT_TIMEOUT_MS = 3000;
20 qCDebug(SerialLinkLog) <<
this;
26 qCDebug(SerialLinkLog) <<
this;
33 qCDebug(SerialLinkLog) <<
this;
71 settings.beginGroup(root);
73 setBaud(settings.value(
"baud", _baud).toInt());
78 setPortName(settings.value(
"portName", _portName).toString());
80 setdtrForceLow(settings.value(
"dtrForceLow", _dtrForceLow).toBool());
87 settings.beginGroup(root);
89 settings.setValue(
"baud", _baud);
90 settings.setValue(
"dataBits", _dataBits);
91 settings.setValue(
"flowControl", _flowControl);
92 settings.setValue(
"stopBits", _stopBits);
93 settings.setValue(
"parity", _parity);
94 settings.setValue(
"portName", _portName);
95 settings.setValue(
"portDisplayName", _portDisplayName);
96 settings.setValue(
"dtrForceLow", _dtrForceLow);
103 static const QSet<qint32> kDefaultSupportedBaudRates = {
150 QSet<qint32> mergedBaudRateSet(kDefaultSupportedBaudRates.constBegin(), kDefaultSupportedBaudRates.constEnd());
151 (void) mergedBaudRateSet.unite(QSet<qint32>(activeSupportedBaudRates.constBegin(), activeSupportedBaudRates.constEnd()));
153 QList<qint32> mergedBaudRateList = mergedBaudRateSet.values();
154 std::sort(mergedBaudRateList.begin(), mergedBaudRateList.end());
156 QStringList supportBaudRateStrings{};
157 supportBaudRateStrings.reserve(mergedBaudRateList.size());
158 for (
const qint32 rate : std::as_const(mergedBaudRateList)) {
159 supportBaudRateStrings.append(QString::number(rate));
162 return supportBaudRateStrings;
169 if (portInfo.systemLocation() ==
name) {
170 return portInfo.portName();
181 , _serialConfig(config)
183 qCDebug(SerialLinkLog) <<
this;
185 (void) qRegisterMetaType<QSerialPort::SerialPortError>(
"QSerialPort::SerialPortError");
192 qCDebug(SerialLinkLog) <<
this;
197 return (_port && _port->isOpen());
207 _timer =
new QTimer(
this);
210 (void) connect(_port, &QSerialPort::aboutToClose,
this, &SerialWorker::_onPortDisconnected);
211 (void) connect(_port, &QSerialPort::readyRead,
this, &SerialWorker::_onPortReadyRead);
218 (void) connect(_timer, &QTimer::timeout,
this, &SerialWorker::_checkPortAvailability);
224 qCWarning(SerialLinkLog) <<
"Already connected to" << _port->
portName();
232 qCWarning(SerialLinkLog) <<
"Not connecting to bootloader" << _port->
portName();
234 _onPortDisconnected();
238 _errorEmitted =
false;
240 qCDebug(SerialLinkLog) <<
"Attempting to open port" << _port->
portName();
241 if (!_port->
open(QIODevice::ReadWrite)) {
242 qCWarning(SerialLinkLog) <<
"Opening port" << _port->
portName() <<
"failed:" << _port->errorString();
246 emit
errorOccurred(tr(
"Could not open port: %1").arg(_port->errorString()));
247 _errorEmitted =
true;
250 _onPortDisconnected();
261 qCDebug(SerialLinkLog) <<
"Already disconnected from port:" << _port->
portName();
265 qCDebug(SerialLinkLog) <<
"Attempting to close port:" << _port->
portName();
272 if (data.isEmpty()) {
282 if (!_port->isWritable()) {
287 qint64 totalBytesWritten = 0;
288 while (totalBytesWritten < data.size()) {
289 const qint64 bytesWritten = _port->write(data.constData() + totalBytesWritten, data.size() - totalBytesWritten);
290 if (bytesWritten == -1) {
291 emit
errorOccurred(tr(
"Could Not Send Data - Write Failed: %1").arg(_port->errorString()));
293 }
else if (bytesWritten == 0) {
294 emit
errorOccurred(tr(
"Could Not Send Data - Write Returned 0 Bytes"));
297 totalBytesWritten += bytesWritten;
300 const QByteArray sent = data.first(totalBytesWritten);
304void SerialWorker::_onPortConnected()
306 qCDebug(SerialLinkLog) <<
"Port connected:" << _port->
portName();
316 _timer->start(CONNECT_TIMEOUT_MS);
319 _errorEmitted =
false;
323void SerialWorker::_onPortDisconnected()
325 qCDebug(SerialLinkLog) <<
"Port disconnected:" << _port->
portName();
331 _errorEmitted =
false;
335void SerialWorker::_onPortReadyRead()
337 const QByteArray data = _port->readAll();
338 if (!data.isEmpty()) {
344void SerialWorker::_onPortBytesWritten(qint64 bytes)
const
346 qCDebug(SerialLinkLog) << _port->
portName() <<
"Wrote" << bytes <<
"bytes";
353 qCDebug(SerialLinkLog) <<
"About to open port" << _port->
portName();
357 qCDebug(SerialLinkLog) <<
"Resource error (likely USB disconnect):" << _port->errorString();
370 qCWarning(SerialLinkLog) <<
"Port error:" << portError <<
errorString;
372 if (!_errorEmitted) {
374 _errorEmitted =
true;
378void SerialWorker::_checkPortAvailability()
384 bool portExists =
false;
404 , _workerThread(new QThread(this))
406 qCDebug(SerialLinkLog) <<
this;
408 _workerThread->setObjectName(QStringLiteral(
"Serial_%1").arg(_serialConfig->
name()));
410 (void) _worker->moveToThread(_workerThread);
413 (void) connect(_workerThread, &QThread::finished, _worker, &QObject::deleteLater);
421 _workerThread->start();
427 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromPort", Qt::BlockingQueuedConnection);
431 _workerThread->quit();
432 if (!_workerThread->wait(DISCONNECT_TIMEOUT_MS)) {
433 qCWarning(SerialLinkLog) <<
"Failed to wait for Serial Thread to close";
436 qCDebug(SerialLinkLog) <<
this;
444bool SerialLink::_connect()
446 return QMetaObject::invokeMethod(_worker,
"connectToPort", Qt::QueuedConnection);
452 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromPort", Qt::QueuedConnection);
456void SerialLink::_onConnected()
458 _disconnectedEmitted =
false;
462void SerialLink::_onDisconnected()
464 if (!_disconnectedEmitted.exchange(
true)) {
469void SerialLink::_onErrorOccurred(
const QString &
errorString)
471 qCWarning(SerialLinkLog) <<
"Communication error:" <<
errorString;
475void SerialLink::_onDataReceived(
const QByteArray &data)
480void SerialLink::_onDataSent(
const QByteArray &data)
485void SerialLink::_writeBytes(
const QByteArray &data)
487 (void) QMetaObject::invokeMethod(_worker,
"writeData", Qt::QueuedConnection, Q_ARG(QByteArray, data));
std::shared_ptr< LinkConfiguration > SharedLinkConfigurationPtr
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Interface holding link specific settings.
virtual void copyFrom(const LinkConfiguration *source)
bool isAutoConnect() const
The link interface defines the interface for all links used to communicate with the ground station ap...
void bytesReceived(LinkInterface *link, const QByteArray &data)
void communicationError(const QString &title, const QString &error)
void bytesSent(LinkInterface *link, const QByteArray &data)
QGC's version of Qt QSerialPortInfo. It provides additional information about board types that QGC ca...
bool isBootloader() const
Provides information about existing serial ports.
static QList< QSerialPortInfo > availablePorts()
Returns a list of available serial ports on the system.
static QList< qint32 > standardBaudRates()
Returns a list of available standard baud rates supported by the target platform.
Provides functions to access serial ports.
bool setDataTerminalReady(bool set)
bool open(OpenMode mode) override
\reimp
void close() override
\reimp
bool setStopBits(StopBits stopBits)
void setPortName(const QString &name)
Sets the name of the serial port.
void errorOccurred(QSerialPort::SerialPortError error)
DataBits
This enum describes the number of data bits used.
Parity
This enum describes the parity scheme used.
SerialPortError error() const
the error status of the serial port
SerialPortError
This enum describes the errors that may be contained by the QSerialPort::error property.
QString portName() const
Returns the name set by setPort() or passed to the QSerialPort constructor.
bool setBaudRate(qint32 baudRate, Directions directions=AllDirections)
StopBits
This enum describes the number of stop bits used.
bool setDataBits(DataBits dataBits)
FlowControl
This enum describes the flow control used.
bool setParity(Parity parity)
bool setFlowControl(FlowControl flowControl)
void setParity(QSerialPort::Parity parity)
QSerialPort::FlowControl flowControl() const
void loadSettings(QSettings &settings, const QString &root) override
QSerialPort::StopBits stopBits() const
void saveSettings(QSettings &settings, const QString &root) const override
void setStopBits(QSerialPort::StopBits stopBits)
void setPortDisplayName(const QString &portDisplayName)
void setBaud(qint32 baud)
SerialConfiguration(const QString &name, QObject *parent=nullptr)
void setDataBits(QSerialPort::DataBits databits)
void setdtrForceLow(bool dtrForceLow)
static QStringList supportedBaudRates()
QString portDisplayName() const
QSerialPort::Parity parity() const
void setUsbDirect(bool usbDirect)
QSerialPort::DataBits dataBits() const
void copyFrom(const LinkConfiguration *source) override
static QString cleanPortDisplayName(const QString &name)
void setFlowControl(QSerialPort::FlowControl flowControl)
void setPortName(const QString &name)
virtual ~SerialConfiguration()
SerialLink(SharedLinkConfigurationPtr &config, QObject *parent=nullptr)
void disconnect() override
bool isConnected() const override
void dataReceived(const QByteArray &data)
void disconnectFromPort()
SerialWorker(const SerialConfiguration *config, QObject *parent=nullptr)
void dataSent(const QByteArray &data)
void writeData(const QByteArray &data)
void errorOccurred(const QString &errorString)