3#include <QtCore/QSettings>
4#include <QtCore/QSignalBlocker>
5#include <QtCore/QThread>
20 qCDebug(SerialLinkLog) <<
this;
26 qCDebug(SerialLinkLog) <<
this;
33 qCDebug(SerialLinkLog) <<
this;
60 qCWarning(SerialLinkLog) <<
"Invalid source configuration type";
80 settings.beginGroup(root);
82 setBaud(settings.value(
"baud", _baud).toInt());
90 setPortName(settings.value(
"portName", _portName).toString());
91 setdtrForceLow(settings.value(
"dtrForceLow", _dtrForceLow).toBool());
98 settings.beginGroup(root);
100 settings.setValue(
"baud", _baud);
101 settings.setValue(
"dataBits", _dataBits);
102 settings.setValue(
"flowControl", _flowControl);
103 settings.setValue(
"stopBits", _stopBits);
104 settings.setValue(
"parity", _parity);
105 settings.setValue(
"portName", _portName);
106 settings.setValue(
"portDisplayName", _portDisplayName);
107 settings.setValue(
"dtrForceLow", _dtrForceLow);
120 const bool bootloader = std::any_of(ports.cbegin(), ports.cend(), [
this](
const auto& port) {
121 return (port.systemLocation == _portName || port.portName == _portName) && port.bootloader;
123 return {_portName, _baud, _dataBits, _flowControl, _stopBits, _parity, _dtrForceLow,
isAutoConnect(), bootloader};
135 : QObject(parent), _settings(std::move(settings)), _reservation(std::move(reservation))
137 qCDebug(SerialLinkLog) <<
this;
139 (void) qRegisterMetaType<QSerialPort::SerialPortError>(
"QSerialPort::SerialPortError");
146 qCDebug(SerialLinkLog) <<
this;
162 (void) connect(_port, &QSerialPort::aboutToClose,
this, &SerialWorker::_onPortDisconnected);
163 (void) connect(_port, &QSerialPort::readyRead,
this, &SerialWorker::_onPortReadyRead);
177 qCWarning(SerialLinkLog) <<
"Already connected to" << _port->
portName();
184 qCWarning(SerialLinkLog) <<
"Not connecting to bootloader" << _port->
portName();
186 _onPortDisconnected();
190 _errorEmitted =
false;
192 qCDebug(SerialLinkLog) <<
"Attempting to open port" << _port->
portName();
193 if (!_port->
open(QIODevice::ReadWrite)) {
196 if (busyAutoConnect) {
197 qCDebug(SerialLinkLog) <<
"Auto-connect port unavailable:" << _port->
portName() << _port->errorString();
199 qCWarning(SerialLinkLog) <<
"Opening port" << _port->
portName() <<
"failed:" << _port->errorString();
203 if (!_errorEmitted && !busyAutoConnect) {
204 emit
errorOccurred(tr(
"Could not open port: %1").arg(_port->errorString()));
205 _errorEmitted =
true;
208 _onPortDisconnected();
213 if (!_configurePort()) {
214 const QString
error = _port->errorString();
224 if (!_port || !_port->isOpen()) {
228 qCDebug(SerialLinkLog) <<
"Attempting to close port:" << _port->
portName();
235 if (data.isEmpty()) {
245 if (!_port->isWritable()) {
250 qint64 totalBytesWritten = 0;
251 while (totalBytesWritten < data.size()) {
252 const qint64 bytesWritten = _port->write(data.constData() + totalBytesWritten, data.size() - totalBytesWritten);
253 if (bytesWritten == -1) {
254 emit
errorOccurred(tr(
"Could Not Send Data - Write Failed: %1").arg(_port->errorString()));
256 }
else if (bytesWritten == 0) {
257 emit
errorOccurred(tr(
"Could Not Send Data - Write Returned 0 Bytes"));
260 totalBytesWritten += bytesWritten;
263 const QByteArray sent = data.first(totalBytesWritten);
267void SerialWorker::_onPortConnected()
269 qCDebug(SerialLinkLog) <<
"Port connected:" << _port->
portName();
272 _errorEmitted =
false;
276void SerialWorker::_onPortDisconnected()
278 qCDebug(SerialLinkLog) <<
"Port disconnected:" << _port->
portName();
280 _isConnected =
false;
281 _errorEmitted =
false;
285void SerialWorker::_onPortReadyRead()
287 const QByteArray data = _port->readAll();
288 if (!data.isEmpty()) {
294void SerialWorker::_onPortBytesWritten(qint64 bytes)
const
296 qCDebug(SerialLinkLog) << _port->
portName() <<
"Wrote" << bytes <<
"bytes";
303 qCDebug(SerialLinkLog) <<
"About to open port" << _port->
portName();
307 qCDebug(SerialLinkLog) <<
"Resource error (likely USB disconnect):" << _port->errorString();
321 qCWarning(SerialLinkLog) <<
"Port error:" << portError <<
errorString;
323 if (!_errorEmitted) {
325 _errorEmitted =
true;
336bool SerialWorker::_configurePort()
339 const QSignalBlocker blocker(_port);
350 qCDebug(SerialLinkLog) <<
"DTR is unavailable on" << _settings.
portName;
360 qCDebug(SerialLinkLog) <<
"RTS is unavailable on" << _settings.
portName;
372 _reservation(std::move(reservation)),
373 _worker(new
SerialWorker(_serialConfig->connectionSettings(), _reservation)),
374 _workerThread(new QThread(this))
376 qCDebug(SerialLinkLog) <<
this;
378 _workerThread->setObjectName(QStringLiteral(
"Serial_%1").arg(_serialConfig->
name()));
380 (void) _worker->moveToThread(_workerThread);
383 (void) connect(_workerThread, &QThread::finished, _worker, &QObject::deleteLater);
394 _workerThread->start();
403 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromPort", Qt::QueuedConnection);
409 qCDebug(SerialLinkLog) <<
this;
417bool SerialLink::_connect()
419 return QMetaObject::invokeMethod(_worker,
"connectToPort", Qt::QueuedConnection);
425 (void) QMetaObject::invokeMethod(_worker,
"disconnectFromPort", Qt::QueuedConnection);
429void SerialLink::_onConnected()
431 _disconnectedEmitted =
false;
435void SerialLink::_onDisconnected()
437 if (!_disconnectedEmitted.exchange(
true)) {
442void SerialLink::_onErrorOccurred(
const QString &
errorString)
444 qCWarning(SerialLinkLog) <<
"Communication error:" <<
errorString;
448void SerialLink::_onDataReceived(
const QByteArray &data)
453void SerialLink::_onDataSent(
const QByteArray &data)
458void SerialLink::_writeBytes(
const QByteArray &data)
460 (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)
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.
bool setRequestToSend(bool set)
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.
@ UnsupportedOperationError
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
bool sikRadio() const
Port was identified as a SiK radio by USB VID/PID at auto-connect. Runtime only, not persisted.
void loadSettings(QSettings &settings, const QString &root) override
QSerialPort::StopBits stopBits() const
void saveSettings(QSettings &settings, const QString &root) const override
SerialConnectionSettings connectionSettings() const
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 setSikRadio(bool sikRadio)
void setPortName(const QString &name)
virtual ~SerialConfiguration()
SerialLink(SharedLinkConfigurationPtr &config, SerialPortManager::ReservationPtr reservation, QObject *parent=nullptr)
void disconnect() override
bool isConnected() const override
static SerialPortManager * instance()
std::shared_ptr< const Reservation > ReservationPtr
static QStringList supportedBaudRates()
QList< Port > availablePorts()
QString displayName(const QString &systemLocation)
void portsEnumerated(const QStringList &availablePorts)
Emitted only after a fresh scan, never for a retained Android snapshot. Includes native names and pat...
void dataReceived(const QByteArray &data)
void disconnectFromPort()
void checkPortAvailability(const QStringList &availablePorts)
void dataSent(const QByteArray &data)
void writeData(const QByteArray &data)
SerialWorker(SerialConnectionSettings settings, SerialPortManager::ReservationPtr reservation={}, QObject *parent=nullptr)
void errorOccurred(const QString &errorString)
Captured on the application thread; changes take effect on the next connection.
QSerialPort::StopBits stopBits
QSerialPort::DataBits dataBits
QSerialPort::FlowControl flowControl
QSerialPort::Parity parity