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 { _jsonBoardInfoKey, QJsonValue::Array, true },
54 { _jsonBoardDescriptionFallbackKey, QJsonValue::Array, true },
55 { _jsonBoardManufacturerFallbackKey, QJsonValue::Array, true },
56 };
57 if (!JsonParsing::validateKeys(json, rootKeyInfoList, errorString)) {
58 qCWarning(QGCSerialPortInfoLog) << errorString;
59 return false;
60 }
61
62 static const QList<JsonParsing::KeyValidateInfo> boardKeyInfoList = {
63 { _jsonVendorIDKey, QJsonValue::Double, true },
64 { _jsonProductIDKey, QJsonValue::Double, true },
65 { _jsonBoardClassKey, QJsonValue::String, true },
66 { _jsonNameKey, QJsonValue::String, true },
67 };
68 const QJsonArray rgBoardInfo = json[_jsonBoardInfoKey].toArray();
69 for (const QJsonValue &jsonValue : rgBoardInfo) {
70 if (!jsonValue.isObject()) {
71 qCWarning(QGCSerialPortInfoLog) << "Entry in boardInfo array is not object";
72 return false;
73 }
74
75 const QJsonObject boardObject = jsonValue.toObject();
76 if (!JsonParsing::validateKeys(boardObject, boardKeyInfoList, errorString)) {
77 qCWarning(QGCSerialPortInfoLog) << errorString;
78 return false;
79 }
80
81 const BoardInfo_t boardInfo = {
82 boardObject[_jsonVendorIDKey].toInt(),
83 boardObject[_jsonProductIDKey].toInt(),
84 _boardClassStringToType(boardObject[_jsonBoardClassKey].toString()),
85 boardObject[_jsonNameKey].toString()
86 };
87 if (boardInfo.boardType == BoardTypeUnknown) {
88 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << boardObject[_jsonBoardClassKey].toString();
89 return false;
90 }
91
92 _boardInfoList.append(boardInfo);
93 }
94
95 static const QList<JsonParsing::KeyValidateInfo> fallbackKeyInfoList = {
96 { _jsonRegExpKey, QJsonValue::String, true },
97 { _jsonBoardClassKey, QJsonValue::String, true },
98 { _jsonAndroidOnlyKey, QJsonValue::Bool, false },
99 };
100 const QJsonArray rgBoardDescriptionFallback = json[_jsonBoardDescriptionFallbackKey].toArray();
101 for (const QJsonValue &jsonValue : rgBoardDescriptionFallback) {
102 if (!jsonValue.isObject()) {
103 qCWarning(QGCSerialPortInfoLog) << "Entry in boardFallback array is not object";
104 return false;
105 }
106
107 const QJsonObject fallbackObject = jsonValue.toObject();
108 if (!JsonParsing::validateKeys(fallbackObject, fallbackKeyInfoList, errorString)) {
109 qCWarning(QGCSerialPortInfoLog) << errorString;
110 return false;
111 }
112
113 const QRegularExpression regExp(fallbackObject[_jsonRegExpKey].toString(), QRegularExpression::CaseInsensitiveOption);
114 if (!regExp.isValid()) {
115 qCWarning(QGCSerialPortInfoLog) << "Invalid regular expression in board description fallback:"
116 << regExp.errorString()
117 << "pattern:" << fallbackObject[_jsonRegExpKey].toString();
118 return false;
119 }
120 const BoardRegExpFallback_t boardFallback = {
121 regExp,
122 _boardClassStringToType(fallbackObject[_jsonBoardClassKey].toString()),
123 fallbackObject[_jsonAndroidOnlyKey].toBool(false)
124 };
125 if (boardFallback.boardType == BoardTypeUnknown) {
126 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << fallbackObject[_jsonBoardClassKey].toString();
127 return false;
128 }
129
130 _boardDescriptionFallbackList.append(boardFallback);
131 }
132
133 const QJsonArray rgBoardManufacturerFallback = json[_jsonBoardManufacturerFallbackKey].toArray();
134 for (const QJsonValue &jsonValue : rgBoardManufacturerFallback) {
135 if (!jsonValue.isObject()) {
136 qCWarning(QGCSerialPortInfoLog) << "Entry in boardFallback array is not object";
137 return false;
138 }
139
140 const QJsonObject fallbackObject = jsonValue.toObject();
141 if (!JsonParsing::validateKeys(fallbackObject, fallbackKeyInfoList, errorString)) {
142 qCWarning(QGCSerialPortInfoLog) << errorString;
143 return false;
144 }
145
146 const QRegularExpression regExp(fallbackObject[_jsonRegExpKey].toString(), QRegularExpression::CaseInsensitiveOption);
147 if (!regExp.isValid()) {
148 qCWarning(QGCSerialPortInfoLog) << "Invalid regular expression in board manufacturer fallback:"
149 << regExp.errorString()
150 << "pattern:" << fallbackObject[_jsonRegExpKey].toString();
151 return false;
152 }
153 const BoardRegExpFallback_t boardFallback = {
154 regExp,
155 _boardClassStringToType(fallbackObject[_jsonBoardClassKey].toString()),
156 fallbackObject[_jsonAndroidOnlyKey].toBool(false)
157 };
158 if (boardFallback.boardType == BoardTypeUnknown) {
159 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << fallbackObject[_jsonBoardClassKey].toString();
160 return false;
161 }
162
163 _boardManufacturerFallbackList.append(boardFallback);
164 }
165
166 _jsonDataValid = true;
167
168 return true;
169}
170
171QGCSerialPortInfo::BoardType_t QGCSerialPortInfo::_boardClassStringToType(const QString &boardClass)
172{
173 static const BoardClassString2BoardType_t rgBoardClass2BoardType[BoardTypeUnknown] = {
174 { _boardTypeToString(BoardTypePixhawk), BoardTypePixhawk },
175 { _boardTypeToString(BoardTypeRTKGPS), BoardTypeRTKGPS },
176 { _boardTypeToString(BoardTypeSiKRadio), BoardTypeSiKRadio },
177 { _boardTypeToString(BoardTypeOpenPilot), BoardTypeOpenPilot },
178 };
179
180 for (const BoardClassString2BoardType_t &board : rgBoardClass2BoardType) {
181 if (boardClass == board.classString) {
182 return board.boardType;
183 }
184 }
185
186 return BoardTypeUnknown;
187}
188
190{
191 boardType = BoardTypeUnknown;
192
193 if (!_loadJsonData()) {
194 return false;
195 }
196
197 if (isNull()) {
198 return false;
199 }
200
201 for (const BoardInfo_t &boardInfo : _boardInfoList) {
202 if ((vendorIdentifier() == boardInfo.vendorId) && ((productIdentifier() == boardInfo.productId) || (boardInfo.productId == 0))) {
203 boardType = boardInfo.boardType;
204 name = boardInfo.name;
205 return true;
206 }
207 }
208
209 Q_ASSERT(boardType == BoardTypeUnknown);
210
211 for (const BoardRegExpFallback_t &boardFallback : _boardDescriptionFallbackList) {
212 if (description().contains(boardFallback.regExp)) {
213#ifndef Q_OS_ANDROID
214 if (boardFallback.androidOnly) {
215 continue;
216 }
217#endif
218 boardType = boardFallback.boardType;
219 name = _boardTypeToString(boardType);
220 return true;
221 }
222 }
223
224 for (const BoardRegExpFallback_t &boardFallback : _boardManufacturerFallbackList) {
225 if (manufacturer().contains(boardFallback.regExp)) {
226#ifndef Q_OS_ANDROID
227 if (boardFallback.androidOnly) {
228 continue;
229 }
230#endif
231 boardType = boardFallback.boardType;
232 name = _boardTypeToString(boardType);
233 return true;
234 }
235 }
236
237 return false;
238}
239
240QString QGCSerialPortInfo::_boardTypeToString(BoardType_t boardType)
241{
242 switch (boardType) {
243 case BoardTypePixhawk:
244 return QStringLiteral("Pixhawk");
246 return QStringLiteral("SiK Radio");
248 return QStringLiteral("OpenPilot");
249 case BoardTypeRTKGPS:
250 return QStringLiteral("RTK GPS");
251 case BoardTypeUnknown:
252 default:
253 return QStringLiteral("Unknown");
254 }
255}
256
257QList<QGCSerialPortInfo> QGCSerialPortInfo::availablePorts()
258{
259 QList<QGCSerialPortInfo> list;
260
261 const QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();
262 for (const QSerialPortInfo &portInfo : availablePorts) {
263 if (isSystemPort(portInfo)) {
264 continue;
265 }
266
267 const QGCSerialPortInfo *const qgcPortInfo = reinterpret_cast<const QGCSerialPortInfo*>(&portInfo);
268 list << *qgcPortInfo;
269 }
270
271 return list;
272}
273
275{
276 BoardType_t boardType;
277 QString name;
278 if (!getBoardInfo(boardType, name)) {
279 return false;
280 }
281
282 return ((boardType == BoardTypePixhawk) && description().contains(QStringLiteral("BL")));
283}
284
286{
287 return description().contains(QStringLiteral("CubeBlack"));
288}
289
291{
292#ifdef Q_OS_MACOS
293 static const QList<QString> systemPortLocations = {
294 QStringLiteral("tty.MALS"),
295 QStringLiteral("tty.SOC"),
296 QStringLiteral("tty.Bluetooth-Incoming-Port"),
297 QStringLiteral("tty.usbserial"),
298 QStringLiteral("tty.usbmodem")
299 };
300 for (const QString &systemPortLocation : systemPortLocations) {
301 if (port.systemLocation().contains(systemPortLocation)) {
302 return true;
303 }
304 }
305#else
306 Q_UNUSED(port);
307#endif
308
309 // TODO: Add Linux (LTE modems, etc) and Windows as needed
310
311 return false;
312}
313
315{
316 BoardType_t boardType;
317 QString name;
318 if (!getBoardInfo(boardType, name)) {
319 return false;
320 }
321
322 static const QList<BoardType_t> flashable = {
325 };
326
327 return flashable.contains(boardType);
328}
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
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
Validates that all required keys are present and that listed keys have the expected type.
QJsonObject openInternalQGCJsonFile(const QString &jsonFilename, const QString &expectedFileType, int minSupportedVersion, int maxSupportedVersion, int &version, QString &errorString, const QStringList &defaultTranslateKeys, const QStringList &defaultArrayIDKeys)