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 "JsonHelper.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 = JsonHelper::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<JsonHelper::KeyValidateInfo> rootKeyInfoList = {
53 { _jsonBoardInfoKey, QJsonValue::Array, true },
54 { _jsonBoardDescriptionFallbackKey, QJsonValue::Array, true },
55 { _jsonBoardManufacturerFallbackKey, QJsonValue::Array, true },
56 };
57 if (!JsonHelper::validateKeys(json, rootKeyInfoList, errorString)) {
58 qCWarning(QGCSerialPortInfoLog) << errorString;
59 return false;
60 }
61
62 static const QList<JsonHelper::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 (!JsonHelper::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<JsonHelper::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 (!JsonHelper::validateKeys(fallbackObject, fallbackKeyInfoList, errorString)) {
109 qCWarning(QGCSerialPortInfoLog) << errorString;
110 return false;
111 }
112
113 const BoardRegExpFallback_t boardFallback = {
114 fallbackObject[_jsonRegExpKey].toString(),
115 _boardClassStringToType(fallbackObject[_jsonBoardClassKey].toString()),
116 fallbackObject[_jsonAndroidOnlyKey].toBool(false)
117 };
118 if (boardFallback.boardType == BoardTypeUnknown) {
119 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << fallbackObject[_jsonBoardClassKey].toString();
120 return false;
121 }
122
123 _boardDescriptionFallbackList.append(boardFallback);
124 }
125
126 const QJsonArray rgBoardManufacturerFallback = json[_jsonBoardManufacturerFallbackKey].toArray();
127 for (const QJsonValue &jsonValue : rgBoardManufacturerFallback) {
128 if (!jsonValue.isObject()) {
129 qCWarning(QGCSerialPortInfoLog) << "Entry in boardFallback array is not object";
130 return false;
131 }
132
133 const QJsonObject fallbackObject = jsonValue.toObject();
134 if (!JsonHelper::validateKeys(fallbackObject, fallbackKeyInfoList, errorString)) {
135 qCWarning(QGCSerialPortInfoLog) << errorString;
136 return false;
137 }
138
139 const BoardRegExpFallback_t boardFallback = {
140 fallbackObject[_jsonRegExpKey].toString(),
141 _boardClassStringToType(fallbackObject[_jsonBoardClassKey].toString()),
142 fallbackObject[_jsonAndroidOnlyKey].toBool(false)
143 };
144 if (boardFallback.boardType == BoardTypeUnknown) {
145 qCWarning(QGCSerialPortInfoLog) << "Bad board class" << fallbackObject[_jsonBoardClassKey].toString();
146 return false;
147 }
148
149 _boardManufacturerFallbackList.append(boardFallback);
150 }
151
152 _jsonDataValid = true;
153
154 return true;
155}
156
157QGCSerialPortInfo::BoardType_t QGCSerialPortInfo::_boardClassStringToType(const QString &boardClass)
158{
159 static const BoardClassString2BoardType_t rgBoardClass2BoardType[BoardTypeUnknown] = {
160 { _boardTypeToString(BoardTypePixhawk), BoardTypePixhawk },
161 { _boardTypeToString(BoardTypeRTKGPS), BoardTypeRTKGPS },
162 { _boardTypeToString(BoardTypeSiKRadio), BoardTypeSiKRadio },
163 { _boardTypeToString(BoardTypeOpenPilot), BoardTypeOpenPilot },
164 };
165
166 for (const BoardClassString2BoardType_t &board : rgBoardClass2BoardType) {
167 if (boardClass == board.classString) {
168 return board.boardType;
169 }
170 }
171
172 return BoardTypeUnknown;
173}
174
176{
177 boardType = BoardTypeUnknown;
178
179 if (!_loadJsonData()) {
180 return false;
181 }
182
183 if (isNull()) {
184 return false;
185 }
186
187 for (const BoardInfo_t &boardInfo : _boardInfoList) {
188 if ((vendorIdentifier() == boardInfo.vendorId) && ((productIdentifier() == boardInfo.productId) || (boardInfo.productId == 0))) {
189 boardType = boardInfo.boardType;
190 name = boardInfo.name;
191 return true;
192 }
193 }
194
195 Q_ASSERT(boardType == BoardTypeUnknown);
196
197 for (const BoardRegExpFallback_t &boardFallback : _boardDescriptionFallbackList) {
198 if (description().contains(QRegularExpression(boardFallback.regExp, QRegularExpression::CaseInsensitiveOption))) {
199#ifndef Q_OS_ANDROID
200 if (boardFallback.androidOnly) {
201 continue;
202 }
203#endif
204 boardType = boardFallback.boardType;
205 name = _boardTypeToString(boardType);
206 return true;
207 }
208 }
209
210 for (const BoardRegExpFallback_t &boardFallback : _boardManufacturerFallbackList) {
211 if (manufacturer().contains(QRegularExpression(boardFallback.regExp, QRegularExpression::CaseInsensitiveOption))) {
212#ifndef Q_OS_ANDROID
213 if (boardFallback.androidOnly) {
214 continue;
215 }
216#endif
217 boardType = boardFallback.boardType;
218 name = _boardTypeToString(boardType);
219 return true;
220 }
221 }
222
223 return false;
224}
225
226QString QGCSerialPortInfo::_boardTypeToString(BoardType_t boardType)
227{
228 switch (boardType) {
229 case BoardTypePixhawk:
230 return QStringLiteral("Pixhawk");
232 return QStringLiteral("SiK Radio");
234 return QStringLiteral("OpenPilot");
235 case BoardTypeRTKGPS:
236 return QStringLiteral("RTK GPS");
237 case BoardTypeUnknown:
238 default:
239 return QStringLiteral("Unknown");
240 }
241}
242
243QList<QGCSerialPortInfo> QGCSerialPortInfo::availablePorts()
244{
245 QList<QGCSerialPortInfo> list;
246
247 const QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();
248 for (const QSerialPortInfo &portInfo : availablePorts) {
249 if (isSystemPort(portInfo)) {
250 continue;
251 }
252
253 const QGCSerialPortInfo *const qgcPortInfo = reinterpret_cast<const QGCSerialPortInfo*>(&portInfo);
254 list << *qgcPortInfo;
255 }
256
257 return list;
258}
259
261{
262 BoardType_t boardType;
263 QString name;
264 if (!getBoardInfo(boardType, name)) {
265 return false;
266 }
267
268 return ((boardType == BoardTypePixhawk) && description().contains(QStringLiteral("BL")));
269}
270
272{
273 return description().contains(QStringLiteral("CubeBlack"));
274}
275
277{
278#ifdef Q_OS_MACOS
279 static const QList<QString> systemPortLocations = {
280 QStringLiteral("tty.MALS"),
281 QStringLiteral("tty.SOC"),
282 QStringLiteral("tty.Bluetooth-Incoming-Port"),
283 QStringLiteral("tty.usbserial"),
284 QStringLiteral("tty.usbmodem")
285 };
286 for (const QString &systemPortLocation : systemPortLocations) {
287 if (port.systemLocation().contains(systemPortLocation)) {
288 return true;
289 }
290 }
291#else
292 Q_UNUSED(port);
293#endif
294
295 // TODO: Add Linux (LTE modems, etc) and Windows as needed
296
297 return false;
298}
299
301{
302 BoardType_t boardType;
303 QString name;
304 if (!getBoardInfo(boardType, name)) {
305 return false;
306 }
307
308 static const QList<BoardType_t> flashable = {
311 };
312
313 return flashable.contains(boardType);
314}
QString errorString
#define QGC_LOGGING_CATEGORY(name, categoryStr)
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
QString manufacturer() const
static QList< QSerialPortInfo > availablePorts()
QString systemLocation() const
bool isNull() const
QString description() const
quint16 vendorIdentifier() const
Provides functions to access serial ports.
Definition qserialport.h:17
QJsonObject openInternalQGCJsonFile(const QString &jsonFilename, const QString &expectedFileType, int minSupportedVersion, int maxSupportedVersion, int &version, QString &errorString)
returned error string if validation fails
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)