QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
QGCSerialPortInfo.cc
Go to the documentation of this file.
1#include "QGCSerialPortInfo.h"
2
3#include "JsonParsing.h"
5
6#include <QtCore/QFile>
7#include <QtCore/QJsonArray>
8#include <QtCore/QJsonDocument>
9#include <QtCore/QJsonObject>
10
11QGC_LOGGING_CATEGORY(QGCSerialPortInfoLog, "Comms.QGCSerialPortInfo")
12
13bool QGCSerialPortInfo::_jsonLoaded = false;
14bool QGCSerialPortInfo::_jsonDataValid = false;
15QList<QGCSerialPortInfo::BoardInfo_t> QGCSerialPortInfo::_boardInfoList;
16QList<QGCSerialPortInfo::BoardRegExpFallback_t> QGCSerialPortInfo::_boardDescriptionFallbackList;
17QList<QGCSerialPortInfo::BoardRegExpFallback_t> QGCSerialPortInfo::_boardManufacturerFallbackList;
18
21{
22 qCDebug(QGCSerialPortInfoLog) << this;
23}
24
26 : QSerialPortInfo(port)
27{
28 qCDebug(QGCSerialPortInfoLog) << this;
29}
30
32{
33 qCDebug(QGCSerialPortInfoLog) << this;
34}
35
36bool QGCSerialPortInfo::_loadJsonData()
37{
38 if (_jsonLoaded) {
39 return _jsonDataValid;
40 }
41
42 _jsonLoaded = true;
43
44 QString errorString;
45 int version;
46 const QJsonObject json = JsonParsing::openInternalQGCJsonFile(QStringLiteral(":/json/USBBoardInfo.json"), QString(_jsonFileTypeValue), 1, 1, version, errorString);
47 if (!errorString.isEmpty()) {
48 qCWarning(QGCSerialPortInfoLog) << "Internal Error:" << errorString;
49 return false;
50 }
51
52 static const QList<JsonParsing::KeyValidateInfo> rootKeyInfoList = {
53 { JsonParsing::jsonFileTypeKey, QJsonValue::String, true }, // Standard header, validated by openInternalQGCJsonFile
54 { JsonParsing::jsonVersionKey, QJsonValue::Double, true }, // Standard header, validated by openInternalQGCJsonFile
55 { "comment", QJsonValue::String, false }, // Developer notes only, never parsed
56 { _jsonBoardInfoKey, QJsonValue::Array, true },
57 { _jsonBoardDescriptionFallbackKey, QJsonValue::Array, true },
58 { _jsonBoardManufacturerFallbackKey, QJsonValue::Array, true },
59 };
60 if (!JsonParsing::validateKeysStrict(json, rootKeyInfoList, errorString)) {
61 qCWarning(QGCSerialPortInfoLog) << errorString;
62 return false;
63 }
64
65 static const QList<JsonParsing::KeyValidateInfo> boardKeyInfoList = {
66 { "comment", QJsonValue::String, false }, // Developer notes only, never parsed
67 { _jsonVendorIDKey, QJsonValue::Double, true },
68 { _jsonProductIDKey, QJsonValue::Double, true },
69 { _jsonBoardClassKey, QJsonValue::String, true },
70 { _jsonNameKey, QJsonValue::String, true },
71 };
72 const QJsonArray rgBoardInfo = json[_jsonBoardInfoKey].toArray();
73 for (const QJsonValue &jsonValue : rgBoardInfo) {
74 if (!jsonValue.isObject()) {
75 qCWarning(QGCSerialPortInfoLog) << "Entry in boardInfo array is not object";
76 return false;
77 }
78
79 const QJsonObject boardObject = jsonValue.toObject();
80 if (!JsonParsing::validateKeysStrict(boardObject, boardKeyInfoList, errorString)) {
81 qCWarning(QGCSerialPortInfoLog) << errorString;
82 return false;
83 }
84
85 const BoardInfo_t boardInfo = {
86 boardObject[_jsonVendorIDKey].toInt(),
87 boardObject[_jsonProductIDKey].toInt(),
88 _boardClassStringToType(boardObject[_jsonBoardClassKey].toString()),
89 boardObject[_jsonNameKey].toString()
90 };
91 if (boardInfo.boardType == BoardTypeUnknown) {
92 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << boardObject[_jsonBoardClassKey].toString();
93 return false;
94 }
95
96 _boardInfoList.append(boardInfo);
97 }
98
99 static const QList<JsonParsing::KeyValidateInfo> fallbackKeyInfoList = {
100 { "comment", QJsonValue::String, false }, // Developer notes only, never parsed
101 { _jsonRegExpKey, QJsonValue::String, true },
102 { _jsonBoardClassKey, QJsonValue::String, true },
103 { _jsonAndroidOnlyKey, QJsonValue::Bool, false },
104 };
105 const QJsonArray rgBoardDescriptionFallback = json[_jsonBoardDescriptionFallbackKey].toArray();
106 for (const QJsonValue &jsonValue : rgBoardDescriptionFallback) {
107 if (!jsonValue.isObject()) {
108 qCWarning(QGCSerialPortInfoLog) << "Entry in boardFallback array is not object";
109 return false;
110 }
111
112 const QJsonObject fallbackObject = jsonValue.toObject();
113 if (!JsonParsing::validateKeysStrict(fallbackObject, fallbackKeyInfoList, errorString)) {
114 qCWarning(QGCSerialPortInfoLog) << errorString;
115 return false;
116 }
117
118 const QRegularExpression regExp(fallbackObject[_jsonRegExpKey].toString(), QRegularExpression::CaseInsensitiveOption);
119 if (!regExp.isValid()) {
120 qCWarning(QGCSerialPortInfoLog) << "Invalid regular expression in board description fallback:"
121 << regExp.errorString()
122 << "pattern:" << fallbackObject[_jsonRegExpKey].toString();
123 return false;
124 }
125 const BoardRegExpFallback_t boardFallback = {
126 regExp,
127 _boardClassStringToType(fallbackObject[_jsonBoardClassKey].toString()),
128 fallbackObject[_jsonAndroidOnlyKey].toBool(false)
129 };
130 if (boardFallback.boardType == BoardTypeUnknown) {
131 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << fallbackObject[_jsonBoardClassKey].toString();
132 return false;
133 }
134
135 _boardDescriptionFallbackList.append(boardFallback);
136 }
137
138 const QJsonArray rgBoardManufacturerFallback = json[_jsonBoardManufacturerFallbackKey].toArray();
139 for (const QJsonValue &jsonValue : rgBoardManufacturerFallback) {
140 if (!jsonValue.isObject()) {
141 qCWarning(QGCSerialPortInfoLog) << "Entry in boardFallback array is not object";
142 return false;
143 }
144
145 const QJsonObject fallbackObject = jsonValue.toObject();
146 if (!JsonParsing::validateKeysStrict(fallbackObject, fallbackKeyInfoList, errorString)) {
147 qCWarning(QGCSerialPortInfoLog) << errorString;
148 return false;
149 }
150
151 const QRegularExpression regExp(fallbackObject[_jsonRegExpKey].toString(), QRegularExpression::CaseInsensitiveOption);
152 if (!regExp.isValid()) {
153 qCWarning(QGCSerialPortInfoLog) << "Invalid regular expression in board manufacturer fallback:"
154 << regExp.errorString()
155 << "pattern:" << fallbackObject[_jsonRegExpKey].toString();
156 return false;
157 }
158 const BoardRegExpFallback_t boardFallback = {
159 regExp,
160 _boardClassStringToType(fallbackObject[_jsonBoardClassKey].toString()),
161 fallbackObject[_jsonAndroidOnlyKey].toBool(false)
162 };
163 if (boardFallback.boardType == BoardTypeUnknown) {
164 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << fallbackObject[_jsonBoardClassKey].toString();
165 return false;
166 }
167
168 _boardManufacturerFallbackList.append(boardFallback);
169 }
170
171 _jsonDataValid = true;
172
173 return true;
174}
175
176QGCSerialPortInfo::BoardType_t QGCSerialPortInfo::_boardClassStringToType(const QString &boardClass)
177{
178 static const BoardClassString2BoardType_t rgBoardClass2BoardType[BoardTypeUnknown] = {
179 { _boardTypeToString(BoardTypePixhawk), BoardTypePixhawk },
180 { _boardTypeToString(BoardTypeRTKGPS), BoardTypeRTKGPS },
181 { _boardTypeToString(BoardTypeSiKRadio), BoardTypeSiKRadio },
182 { _boardTypeToString(BoardTypeOpenPilot), BoardTypeOpenPilot },
183 };
184
185 for (const BoardClassString2BoardType_t &board : rgBoardClass2BoardType) {
186 if (boardClass == board.classString) {
187 return board.boardType;
188 }
189 }
190
191 return BoardTypeUnknown;
192}
193
195{
196 boardType = BoardTypeUnknown;
197
198 if (!_loadJsonData()) {
199 return false;
200 }
201
202 if (isNull()) {
203 return false;
204 }
205
206 for (const BoardInfo_t &boardInfo : _boardInfoList) {
207 if ((vendorIdentifier() == boardInfo.vendorId) && ((productIdentifier() == boardInfo.productId) || (boardInfo.productId == 0))) {
208 boardType = boardInfo.boardType;
209 name = boardInfo.name;
210 return true;
211 }
212 }
213
214 Q_ASSERT(boardType == BoardTypeUnknown);
215
216 for (const BoardRegExpFallback_t &boardFallback : _boardDescriptionFallbackList) {
217 if (description().contains(boardFallback.regExp)) {
218#ifndef Q_OS_ANDROID
219 if (boardFallback.androidOnly) {
220 continue;
221 }
222#endif
223 boardType = boardFallback.boardType;
224 name = _boardTypeToString(boardType);
225 return true;
226 }
227 }
228
229 for (const BoardRegExpFallback_t &boardFallback : _boardManufacturerFallbackList) {
230 if (manufacturer().contains(boardFallback.regExp)) {
231#ifndef Q_OS_ANDROID
232 if (boardFallback.androidOnly) {
233 continue;
234 }
235#endif
236 boardType = boardFallback.boardType;
237 name = _boardTypeToString(boardType);
238 return true;
239 }
240 }
241
242 return false;
243}
244
245QString QGCSerialPortInfo::_boardTypeToString(BoardType_t boardType)
246{
247 switch (boardType) {
248 case BoardTypePixhawk:
249 return QStringLiteral("Pixhawk");
251 return QStringLiteral("SiK Radio");
253 return QStringLiteral("OpenPilot");
254 case BoardTypeRTKGPS:
255 return QStringLiteral("RTK GPS");
256 case BoardTypeUnknown:
257 default:
258 return QStringLiteral("Unknown");
259 }
260}
261
262QList<QGCSerialPortInfo> QGCSerialPortInfo::availablePorts()
263{
264 QList<QGCSerialPortInfo> list;
265
266 const QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();
267 for (const QSerialPortInfo &portInfo : availablePorts) {
268 if (isSystemPort(portInfo)) {
269 continue;
270 }
271
272 const QGCSerialPortInfo *const qgcPortInfo = reinterpret_cast<const QGCSerialPortInfo*>(&portInfo);
273 list << *qgcPortInfo;
274 }
275
276 return list;
277}
278
280{
281 BoardType_t boardType;
282 QString name;
283 if (!getBoardInfo(boardType, name)) {
284 return false;
285 }
286
287 return ((boardType == BoardTypePixhawk) && description().contains(QStringLiteral("BL")));
288}
289
291{
292 return description().contains(QStringLiteral("CubeBlack"));
293}
294
296{
297#ifdef Q_OS_MACOS
298 static const QList<QString> systemPortLocations = {
299 QStringLiteral("tty.MALS"),
300 QStringLiteral("tty.SOC"),
301 QStringLiteral("tty.Bluetooth-Incoming-Port"),
302 QStringLiteral("tty.usbserial"),
303 QStringLiteral("tty.usbmodem")
304 };
305 for (const QString &systemPortLocation : systemPortLocations) {
306 if (port.systemLocation().contains(systemPortLocation)) {
307 return true;
308 }
309 }
310#else
311 Q_UNUSED(port);
312#endif
313
314 // TODO: Add Linux (LTE modems, etc) and Windows as needed
315
316 return false;
317}
318
320{
321 BoardType_t boardType;
322 QString name;
323 if (!getBoardInfo(boardType, name)) {
324 return false;
325 }
326
327 static const QList<BoardType_t> flashable = {
330 };
331
332 return flashable.contains(boardType);
333}
QString errorString
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QGC's version of Qt QSerialPortInfo. It provides additional information about board types that QGC ca...
static bool isSystemPort(const QSerialPortInfo &port)
bool getBoardInfo(BoardType_t &boardType, QString &name) const
static QList< QGCSerialPortInfo > availablePorts()
Override of QSerialPortInfo::availablePorts.
Provides information about existing serial ports.
quint16 productIdentifier() const
Returns the 16-bit product number for the serial port, if available; otherwise returns zero.
QString manufacturer() const
Returns the manufacturer string of the serial port, if available; otherwise returns an empty string.
static QList< QSerialPortInfo > availablePorts()
Returns a list of available serial ports on the system.
QString systemLocation() const
Returns the system location of the serial port.
bool isNull() const
Returns whether this QSerialPortInfo object holds a serial port definition.
QString description() const
Returns the description string of the serial port, if available; otherwise returns an empty string.
quint16 vendorIdentifier() const
Returns the 16-bit vendor number for the serial port, if available; otherwise returns zero.
Provides functions to access serial ports.
Definition qserialport.h:17
constexpr const char * jsonFileTypeKey
Definition JsonParsing.h:13
QJsonObject openInternalQGCJsonFile(const QString &jsonFilename, const QString &expectedFileType, int minSupportedVersion, int maxSupportedVersion, int &version, QString &errorString, const QStringList &defaultTranslateKeys, const QStringList &defaultArrayIDKeys)
bool validateKeysStrict(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
Validates keys like validateKeys but also rejects any keys not listed in keyInfo.
constexpr const char * jsonVersionKey
Definition JsonParsing.h:12