4#include <QtCore/QSettings>
5#include <QtCore/QThread>
6#include <QtCore/QTimer>
11 constexpr int CONNECT_TIMEOUT_MS = 1000;
19 qCDebug(SerialLinkLog) <<
this;
25 qCDebug(SerialLinkLog) <<
this;
32 qCDebug(SerialLinkLog) <<
this;
74 settings.beginGroup(root);
76 setBaud(settings.value(
"baud", _baud).toInt());
84 setPortName(settings.value(
"portName", _portName).toString());
85 setdtrForceLow(settings.value(
"dtrForceLow", _dtrForceLow).toBool());
92 settings.beginGroup(root);
94 settings.setValue(
"baud", _baud);
95 settings.setValue(
"dataBits", _dataBits);
96 settings.setValue(
"flowControl", _flowControl);
97 settings.setValue(
"stopBits", _stopBits);
98 settings.setValue(
"parity", _parity);
99 settings.setValue(
"portName", _portName);
100 settings.setValue(
"portDisplayName", _portDisplayName);
101 settings.setValue(
"dtrForceLow", _dtrForceLow);
108 static const QSet<qint32> kDefaultSupportedBaudRates = {
155 QSet<qint32> mergedBaudRateSet(kDefaultSupportedBaudRates.constBegin(), kDefaultSupportedBaudRates.constEnd());
156 (void) mergedBaudRateSet.unite(QSet<qint32>(activeSupportedBaudRates.constBegin(), activeSupportedBaudRates.constEnd()));
158 QList<qint32> mergedBaudRateList = mergedBaudRateSet.values();
159 std::sort(mergedBaudRateList.begin(), mergedBaudRateList.end());
161 QStringList supportBaudRateStrings{};
162 supportBaudRateStrings.reserve(mergedBaudRateList.size());
163 for (
const qint32 rate : std::as_const(mergedBaudRateList)) {
164 supportBaudRateStrings.append(QString::number(rate));
167 return supportBaudRateStrings;
174 if (portInfo.systemLocation() ==
name) {
179 if (!portInfo.description().isEmpty()) {
180 displayName = portInfo.description();
181 }
else if (!portInfo.manufacturer().isEmpty()) {
182 displayName = portInfo.manufacturer();
184 if (!displayName.isEmpty()) {
185 return QStringLiteral(
"%1 (%2)").arg(displayName, portInfo.portName());
188 return portInfo.portName();
201 qCDebug(SerialLinkLog) <<
this;
203 (void) qRegisterMetaType<QSerialPort::SerialPortError>(
"QSerialPort::SerialPortError");
210 qCDebug(SerialLinkLog) <<
this;
215 return (_port && _port->isOpen());
225 _timer =
new QTimer(
this);
228 (void) connect(_port, &QSerialPort::aboutToClose,
this, &SerialWorker::_onPortDisconnected);
229 (void) connect(_port, &QSerialPort::readyRead,
this, &SerialWorker::_onPortReadyRead);
236 (void) connect(_timer, &QTimer::timeout,
this, &SerialWorker::_checkPortAvailability);
242 qCWarning(SerialLinkLog) <<
"Already connected to" << _port->
portName();
250 qCWarning(SerialLinkLog) <<
"Not connecting to bootloader" << _port->
portName();
252 _onPortDisconnected();
256 _errorEmitted =
false;
258 qCDebug(SerialLinkLog) <<
"Attempting to open port" << _port->
portName();
259 if (!_port->
open(QIODevice::ReadWrite)) {
260 qCWarning(SerialLinkLog) <<
"Opening port" << _port->
portName() <<
"failed:" << _port->errorString();
264 emit
errorOccurred(tr(
"Could not open port: %1").arg(_port->errorString()));
265 _errorEmitted =
true;
268 _onPortDisconnected();
279 qCDebug(SerialLinkLog) <<
"Already disconnected from port:" << _port->
portName();
283 qCDebug(SerialLinkLog) <<
"Attempting to close port:" << _port->
portName();
290 if (data.isEmpty()) {
300 if (!_port->isWritable()) {
305 qint64 totalBytesWritten = 0;
306 while (totalBytesWritten < data.size()) {
307 const qint64 bytesWritten = _port->write(data.constData() + totalBytesWritten, data.size() - totalBytesWritten);
308 if (bytesWritten == -1) {
309 emit
errorOccurred(tr(
"Could Not Send Data - Write Failed: %1").arg(_port->errorString()));
311 }
else if (bytesWritten == 0) {
312 emit
errorOccurred(tr(
"Could Not Send Data - Write Returned 0 Bytes"));
315 totalBytesWritten += bytesWritten;
318 const QByteArray sent = data.first(totalBytesWritten);
322void SerialWorker::_onPortConnected()
324 qCDebug(SerialLinkLog) <<
"Port connected:" << _port->
portName();
334 _timer->start(CONNECT_TIMEOUT_MS);
337 _errorEmitted =
false;
341void SerialWorker::_onPortDisconnected()
343 qCDebug(SerialLinkLog) <<
"Port disconnected:" << _port->
portName();
349 _errorEmitted =
false;
353void SerialWorker::_onPortReadyRead()
355 const QByteArray data = _port->readAll();
356 if (!data.isEmpty()) {
362void SerialWorker::_onPortBytesWritten(qint64 bytes)
const
364 qCDebug(SerialLinkLog) << _port->
portName() <<
"Wrote" << bytes <<
"bytes";
371 qCDebug(SerialLinkLog) <<
"About to open port" << _port->
portName();
375 qCDebug(SerialLinkLog) <<
"Resource error (likely USB disconnect):" << _port->errorString();
388 qCWarning(SerialLinkLog) <<
"Port error:" << portError <<
errorString;
390 if (!_errorEmitted) {
392 _errorEmitted =
true;
396void SerialWorker::_checkPortAvailability()
402 bool portExists =
false;
403 const QString configuredPort = _serialConfig->
portName();
408 if ((info.systemLocation() == configuredPort) || (info.portName() == configuredPort)) {
425 , _workerThread(new QThread(this))
427 qCDebug(SerialLinkLog) <<
this;
429 _workerThread->setObjectName(QStringLiteral(
"Serial_%1").arg(_serialConfig->
name()));
431 (void) _worker->moveToThread(_workerThread);
434 (void) connect(_workerThread, &QThread::finished, _worker, &QObject::deleteLater);
442 _workerThread->start();
451 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromPort", Qt::QueuedConnection);
457 qCDebug(SerialLinkLog) <<
this;
465bool SerialLink::_connect()
467 return QMetaObject::invokeMethod(_worker,
"connectToPort", Qt::QueuedConnection);
473 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromPort", Qt::QueuedConnection);
477void SerialLink::_onConnected()
479 _disconnectedEmitted =
false;
483void SerialLink::_onDisconnected()
485 if (!_disconnectedEmitted.exchange(
true)) {
490void SerialLink::_onErrorOccurred(
const QString &
errorString)
492 qCWarning(SerialLinkLog) <<
"Communication error:" <<
errorString;
496void SerialLink::_onDataReceived(
const QByteArray &data)
501void SerialLink::_onDataSent(
const QByteArray &data)
506void SerialLink::_writeBytes(
const QByteArray &data)
508 (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 _shutdownWorkerThread(QThread *thread, const QLoggingCategory &category, bool allowTerminate=true)
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)