QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
SerialPortManager.cc
Go to the documentation of this file.
1#include "SerialPortManager.h"
2
3#include <QtCore/QApplicationStatic>
4#include <QtCore/QSet>
5
6#include <algorithm>
7#include <iterator>
8#include <utility>
9
10#include "QGCLoggingCategory.h"
11
12QGC_LOGGING_CATEGORY(SerialPortManagerLog, "Comms.Serial.SerialPortManager")
13Q_APPLICATION_STATIC(SerialPortManager, _serialPortManager)
14
15SerialPortManager::SerialPortManager(QObject* parent, Enumerator enumerator)
16 : QObject(parent), _enumerator(enumerator ? std::move(enumerator) : &_enumeratePorts)
17{}
18
20{
21 return _serialPortManager();
22}
23
24bool SerialPortManager::isPrimaryInterface(const Port& port, QSet<QString>& seenDevices)
25{
26 if (port.physicalDeviceId.isEmpty()) {
27 return true;
28 }
29 const qsizetype seen = seenDevices.size();
30 seenDevices.insert(port.physicalDeviceId);
31 return seenDevices.size() != seen;
32}
33
34QList<SerialPortManager::Port> SerialPortManager::_enumeratePorts()
35{
36 QList<Port> ports;
38 Port port;
39 if (info.hasVendorIdentifier() && info.hasProductIdentifier() && !info.serialNumber().isEmpty() &&
40 info.serialNumber() != QStringLiteral("0")) {
41 port.physicalDeviceId = QStringLiteral("%1:%2:%3")
42 .arg(info.vendorIdentifier())
43 .arg(info.productIdentifier())
44 .arg(info.serialNumber());
45 }
46 port.description = info.description();
47 port.systemLocation = info.systemLocation().trimmed();
48 port.portName = info.portName().trimmed();
49 port.displayName = port.portName;
50#ifdef Q_OS_ANDROID
51 const QString label = port.description.isEmpty() ? info.manufacturer() : port.description;
52 if (!label.isEmpty()) {
53 port.displayName = QStringLiteral("%1 (%2)").arg(label, port.portName);
54 }
55#endif
56 (void) info.getBoardInfo(port.boardType, port.boardName);
57 port.bootloader = info.isBootloader();
58 ports.append(port);
59 }
60 return ports;
61}
62
63QList<SerialPortManager::Port> SerialPortManager::availablePorts()
64{
65 // Java USB enumeration leaks handles while a port is occupied. Preserve the last
66 // snapshot instead of reporting an empty inventory and falsely declaring an unplug.
67 if ((_singlePortOnly && anyPortReserved()) || (_scanTimer.isValid() && _scanTimer.elapsed() < 1000)) {
68 return _ports;
69 }
70 _ports = _enumerator();
71 _scanTimer.restart();
72 QStringList identities;
73 QStringList serialPorts;
74 serialPorts.reserve(_ports.size());
75 for (const Port& port : std::as_const(_ports)) {
76 serialPorts.append(port.systemLocation);
77 identities.append(port.systemLocation);
78 identities.append(port.portName);
79 }
80 if (_serialPorts != serialPorts) {
81 _serialPorts = std::move(serialPorts);
82 emit serialPortsChanged();
83 }
84 emit portsEnumerated(identities);
85 return _ports;
86}
87
89{
90 _scanTimer.invalidate();
91 (void) availablePorts();
92}
93
94QString SerialPortManager::displayName(const QString& systemLocation)
95{
96 const QString name = systemLocation.trimmed();
97 const auto ports = availablePorts();
98 for (const auto& port : ports) {
99 if (port.systemLocation == name || port.portName == name) {
100 return port.displayName.isEmpty() ? port.portName : port.displayName;
101 }
102 }
103 return {};
104}
105
107{
108 const QString port = systemLocation.trimmed();
109 if (!canReservePort(port)) {
110 return {};
111 }
112 for (auto it = _reservations.begin(); it != _reservations.end();) {
113 it = it.value().expired() ? _reservations.erase(it) : std::next(it);
114 }
115 auto reservation = std::make_shared<const Reservation>(Reservation{port});
116 _reservations.insert(port, reservation);
117 return reservation;
118}
119
120bool SerialPortManager::isPortReserved(const QString& systemLocation) const
121{
122 return !_reservations.value(systemLocation.trimmed()).expired();
123}
124
126{
127 for (const auto& reservation : _reservations) {
128 if (!reservation.expired()) {
129 return true;
130 }
131 }
132 return false;
133}
134
135bool SerialPortManager::canReservePort(const QString& systemLocation) const
136{
137 return !systemLocation.trimmed().isEmpty() && !isPortReserved(systemLocation) &&
138 !(_singlePortOnly && anyPortReserved());
139}
140
142{
143 const QString port = systemLocation.trimmed();
144 if (port.isEmpty()) {
145 return {};
146 }
147 for (auto it = _autoConnectExclusions.begin(); it != _autoConnectExclusions.end();) {
148 it = it.value().expired() ? _autoConnectExclusions.erase(it) : std::next(it);
149 }
150 if (auto existing = _autoConnectExclusions.value(port).lock()) {
151 return existing;
152 }
153 auto exclusion = std::make_shared<const Reservation>(Reservation{port});
154 _autoConnectExclusions.insert(port, exclusion);
155 return exclusion;
156}
157
158bool SerialPortManager::canAutoConnectPort(const QString& systemLocation) const
159{
160 return !isAutoConnectExcluded(systemLocation) && canReservePort(systemLocation);
161}
162
164{
165 static const QSet<qint32> kDefaultSupportedBaudRates = {
166#ifdef Q_OS_UNIX
167 50, 75,
168#endif
169 110,
170#ifdef Q_OS_UNIX
171 150, 200, 134,
172#endif
173 300, 600, 1200,
174#ifdef Q_OS_UNIX
175 1800,
176#endif
177 2400, 4800, 9600,
178#ifdef Q_OS_WIN
179 14400,
180#endif
181 19200, 38400,
182#ifdef Q_OS_WIN
183 56000,
184#endif
185 57600, 115200,
186#ifdef Q_OS_WIN
187 128000,
188#endif
189 230400,
190#ifdef Q_OS_WIN
191 256000,
192#endif
193 460800, 500000,
194#ifdef Q_OS_LINUX
195 576000,
196#endif
197 921600,
198 };
199
200 const QList<qint32> activeSupportedBaudRates = QSerialPortInfo::standardBaudRates();
201
202 QSet<qint32> mergedBaudRateSet(kDefaultSupportedBaudRates.constBegin(), kDefaultSupportedBaudRates.constEnd());
203 (void) mergedBaudRateSet.unite(
204 QSet<qint32>(activeSupportedBaudRates.constBegin(), activeSupportedBaudRates.constEnd()));
205
206 QList<qint32> mergedBaudRateList = mergedBaudRateSet.values();
207 std::sort(mergedBaudRateList.begin(), mergedBaudRateList.end());
208
209 QStringList supportBaudRateStrings{};
210 supportBaudRateStrings.reserve(mergedBaudRateList.size());
211 for (const qint32 rate : std::as_const(mergedBaudRateList)) {
212 supportBaudRateStrings.append(QString::number(rate));
213 }
214
215 return supportBaudRateStrings;
216}
217
218bool SerialPortManager::isAutoConnectExcluded(const QString& systemLocation) const
219{
220 return !_autoConnectExclusions.value(systemLocation.trimmed()).expired();
221}
Q_APPLICATION_STATIC(ADSBVehicleManager, _adsbVehicleManager, SettingsManager::instance() ->adsbVehicleManagerSettings())
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QGC's version of Qt QSerialPortInfo. It provides additional information about board types that QGC ca...
static QList< qint32 > standardBaudRates()
Returns a list of available standard baud rates supported by the target platform.
Shared serial inventory and exclusive claims. Called on the application thread.
static SerialPortManager * instance()
bool anyPortReserved() const
std::shared_ptr< const Reservation > ReservationPtr
static QStringList supportedBaudRates()
bool canReservePort(const QString &systemLocation) const
bool isAutoConnectExcluded(const QString &systemLocation) const
void serialPortsChanged()
bool isPortReserved(const QString &systemLocation) const
bool canAutoConnectPort(const QString &systemLocation) const
static bool isPrimaryInterface(const Port &port, QSet< QString > &seenDevices)
ReservationPtr excludeFromAutoConnect(const QString &systemLocation)
Routing exclusions survive reconnects without marking the hardware occupied.
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...
std::function< QList< Port >()> Enumerator
ReservationPtr reservePort(const QString &systemLocation)
void rescan()
As availablePorts(), without reusing a scan made less than a second ago.
QStringList serialPorts() const
GPSCommandSequence port(QByteArrayView port, unsigned baud)
Clears the SBF output of port, keeps a serial port at the link's baud, and selects SBF and the WGS84 ...
Definition SBFPlan.cc:34