QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
FirmwarePlugin.cc
Go to the documentation of this file.
1 #include "FirmwarePlugin.h"
2#include "AutoPilotPlugin.h"
3#include "Autotune.h"
5#include "MAVLinkProtocol.h"
6#include "QGCApplication.h"
7#include "QGCCameraManager.h"
8#include "QGCFileDownload.h"
11#include "VehicleComponent.h"
12
13#include <QtCore/QRegularExpression>
14#include <QtCore/QThread>
15
16QGC_LOGGING_CATEGORY(FirmwarePluginLog, "FirmwarePlugin.FirmwarePlugin")
17
18static const QString guided_mode_not_supported_by_vehicle = QObject::tr("Guided mode not supported by Vehicle.");
19
21 : QObject(parent)
22{
23 qCDebug(FirmwarePluginLog) << this;
24}
25
27{
28 qCDebug(FirmwarePluginLog) << this;
29}
30
32{
33 return new GenericAutoPilotPlugin(vehicle, vehicle);
34}
35
36QString FirmwarePlugin::flightMode(uint8_t base_mode, uint32_t custom_mode) const
37{
38 Q_UNUSED(custom_mode);
39
40 struct Bit2Name {
41 const uint8_t baseModeBit;
42 const char *name;
43 };
44
45 static constexpr Bit2Name rgBit2Name[] = {
46 { MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, "Manual" },
47 { MAV_MODE_FLAG_STABILIZE_ENABLED, "Stabilize" },
48 { MAV_MODE_FLAG_GUIDED_ENABLED, "Guided" },
49 { MAV_MODE_FLAG_AUTO_ENABLED, "Auto" },
50 { MAV_MODE_FLAG_TEST_ENABLED, "Test" },
51 };
52
53 QString flightMode;
54 if (base_mode == 0) {
55 flightMode = "PreFlight";
56 } else if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
57 flightMode = _modeEnumToString.value(custom_mode, QStringLiteral("Custom:0x%1").arg(custom_mode, 0, 16));
58 } else {
59 for (size_t i = 0; i < std::size(rgBit2Name); i++) {
60 if (base_mode & rgBit2Name[i].baseModeBit) {
61 if (i != 0) {
62 flightMode += " ";
63 }
64 flightMode += rgBit2Name[i].name;
65 }
66 }
67 }
68
69 return flightMode;
70}
71
72bool FirmwarePlugin::setFlightMode(const QString &flightMode, uint8_t *base_mode, uint32_t *custom_mode) const
73{
74 Q_UNUSED(flightMode);
75 Q_UNUSED(base_mode);
76 Q_UNUSED(custom_mode);
77
78 qCWarning(FirmwarePluginLog) << "FirmwarePlugin::setFlightMode called on base class, not supported";
79
80 return false;
81}
82
84{
85 switch (vehicleClass) {
87 return QStringLiteral(":/json/MavCmdInfoCommon.json");
89 return QStringLiteral(":/json/MavCmdInfoFixedWing.json");
91 return QStringLiteral(":/json/MavCmdInfoMultiRotor.json");
93 return QStringLiteral(":/json/MavCmdInfoVTOL.json");
95 return QStringLiteral(":/json/MavCmdInfoSub.json");
97 return QStringLiteral(":/json/MavCmdInfoRover.json");
98 default:
99 qCWarning(FirmwarePluginLog) << "FirmwarePlugin::missionCommandOverrides called with bad VehicleClass_t:" << vehicleClass;
100 return QString();
101 }
102}
103
104void FirmwarePlugin::_getParameterMetaDataVersionInfo(const QString &metaDataFile, int &majorVersion, int &minorVersion) const
105{
106 Q_UNUSED(metaDataFile);
107 majorVersion = -1;
108 minorVersion = -1;
109}
110
111void FirmwarePlugin::setGuidedMode(Vehicle *vehicle, bool guidedMode) const
112{
113 Q_UNUSED(vehicle);
114 Q_UNUSED(guidedMode);
116}
117
119{
120 Q_UNUSED(vehicle);
122}
123
124void FirmwarePlugin::guidedModeRTL(Vehicle *vehicle, bool smartRTL) const
125{
126 Q_UNUSED(vehicle);
127 Q_UNUSED(smartRTL);
129}
130
132{
133 Q_UNUSED(vehicle);
135}
136
137void FirmwarePlugin::guidedModeTakeoff(Vehicle *vehicle, double takeoffAltRel) const
138{
139 Q_UNUSED(vehicle);
140 Q_UNUSED(takeoffAltRel);
142}
143
144void FirmwarePlugin::guidedModeGotoLocation(Vehicle *vehicle, const QGeoCoordinate &gotoCoord, double forwardFlightLoiterRadius) const
145{
146 Q_UNUSED(vehicle);
147 Q_UNUSED(gotoCoord);
148 Q_UNUSED(forwardFlightLoiterRadius);
150}
151
152void FirmwarePlugin::guidedModeChangeAltitude(Vehicle*, double, bool pauseVehicle)
153{
154 Q_UNUSED(pauseVehicle);
156}
157
162
167
168void FirmwarePlugin::guidedModeChangeHeading(Vehicle *vehicle, const QGeoCoordinate &/*headingCoord*/) const
169{
170 Q_UNUSED(vehicle);
172}
173
175{
176 // Not supported by generic vehicle
178}
179
184
191
192const QVariantList &FirmwarePlugin::toolIndicators(const Vehicle*)
193{
194 //-- Default list of indicators for all vehicles.
195 if (_toolIndicatorList.isEmpty()) {
196 _toolIndicatorList = QVariantList({
197 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/VehicleGPSIndicator.qml")),
198 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/GPSResilienceIndicator.qml")),
199 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/TelemetryRSSIIndicator.qml")),
200 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/RCRSSIIndicator.qml")),
201 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/BatteryIndicator.qml")),
202 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/RemoteIDIndicator.qml")),
203 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/GimbalIndicator.qml")),
204 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/EscIndicator.qml")),
205 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/JoystickIndicator.qml")),
206 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/MultiVehicleSelector.qml")),
207#ifdef QT_DEBUG
208 // ControlIndicator is only available in debug builds for the moment
209 QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/GCSControlIndicator.qml")),
210#endif
211 });
212 }
213
214 return _toolIndicatorList;
215}
216
218{
219 if (vehicle->armed()) {
220 return true;
221 }
222
223 bool vehicleArmed = false;
224
225 // Only try arming the vehicle a single time. Doing retries on arming with a delay can lead to safety issues.
226 vehicle->setArmed(true, false /* showError */);
227
228 // Wait 1500 msecs for vehicle to arm (waiting for the next heartbeat)
229 for (int i = 0; i < 15; i++) {
230 if (vehicle->armed()) {
231 vehicleArmed = true;
232 break;
233 }
234 QThread::msleep(100);
235 QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
236 }
237
238 return vehicleArmed;
239}
240
241bool FirmwarePlugin::_setFlightModeAndValidate(Vehicle *vehicle, const QString &flightMode) const
242{
243 if (vehicle->flightMode() == flightMode) {
244 return true;
245 }
246
247 bool flightModeChanged = false;
248
249 // We try 3 times
250 for (int retries = 0; retries < 3; retries++) {
251 vehicle->setFlightMode(flightMode);
252
253 // Wait for vehicle to return flight mode
254 for (int i = 0; i < 13; i++) {
255 if (vehicle->flightMode() == flightMode) {
256 flightModeChanged = true;
257 break;
258 }
259 QThread::msleep(100);
260 QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
261 }
262
263 if (flightModeChanged) {
264 break;
265 }
266 }
267
268 return flightModeChanged;
269}
270
271
272void FirmwarePlugin::batteryConsumptionData(Vehicle *vehicle, int &mAhBattery, double &hoverAmps, double &cruiseAmps) const
273{
274 Q_UNUSED(vehicle);
275 mAhBattery = 0;
276 hoverAmps = 0;
277 cruiseAmps = 0;
278}
279
280bool FirmwarePlugin::hasGimbal(Vehicle *vehicle, bool &rollSupported, bool &pitchSupported, bool &yawSupported) const
281{
282 Q_UNUSED(vehicle);
283 rollSupported = false;
284 pitchSupported = false;
285 yawSupported = false;
286 return false;
287}
288
290{
291 return new QGCCameraManager(vehicle);
292}
293
294MavlinkCameraControl *FirmwarePlugin::createCameraControl(const mavlink_camera_information_t *info, Vehicle *vehicle, int compID, QObject *parent) const
295{
296 return new VehicleCameraControl(info, vehicle, compID, parent);
297}
298
300{
301 // This is required as mocklink uses a hardcoded firmware version
302 if (qgcApp()->runningUnitTests()) {
303 qCDebug(FirmwarePluginLog) << "Skipping version check";
304 return;
305 }
306
307 const QString versionFile = _getLatestVersionFileUrl(vehicle);
308 qCDebug(FirmwarePluginLog) << "Downloading" << versionFile;
309 QGCFileDownload *const downloader = new QGCFileDownload(vehicle);
310 (void) connect(downloader, &QGCFileDownload::finished, this, [vehicle, this, versionFile](bool success, const QString &localFile, const QString &errorMsg) {
311 if (success) {
312 _versionFileDownloadFinished(versionFile, localFile, vehicle);
313 } else if (!errorMsg.isEmpty()) {
314 qCDebug(FirmwarePluginLog) << "Failed to download the latest fw version file. Error:" << errorMsg;
315 }
316 sender()->deleteLater();
317 });
318
319 if (!downloader->start(versionFile)) {
320 downloader->deleteLater();
321 }
322}
323
324void FirmwarePlugin::_versionFileDownloadFinished(const QString &remoteFile, const QString &localFile, const Vehicle *vehicle) const
325{
326 qCDebug(FirmwarePluginLog) << "Download complete" << remoteFile << localFile;
327 // Now read the version file and pull out the version string
328 QFile versionFile(localFile);
329 if (!versionFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
330 qCWarning(FirmwarePluginLog) << "Error opening downloaded version file.";
331 return;
332 }
333
334 QTextStream stream(&versionFile);
335 const QString versionFileContents = stream.readAll();
336 QString version;
337 const QRegularExpressionMatch match = QRegularExpression(_versionRegex()).match(versionFileContents);
338
339 qCDebug(FirmwarePluginLog) << "Looking for version number...";
340
341 if (match.hasMatch()) {
342 version = match.captured(1);
343 } else {
344 qCWarning(FirmwarePluginLog) << "Unable to parse version info from file" << remoteFile;
345 return;
346 }
347
348 qCDebug(FirmwarePluginLog) << "Latest stable version = " << version;
349
350 const int currType = vehicle->firmwareVersionType();
351
352 // Check if lower version than stable or same version but different type
353 if ((currType == FIRMWARE_VERSION_TYPE_OFFICIAL) && (vehicle->versionCompare(version) < 0)) {
354 const QString currentVersionNumber = QStringLiteral("%1.%2.%3").arg(vehicle->firmwareMajorVersion())
355 .arg(vehicle->firmwareMinorVersion())
356 .arg(vehicle->firmwarePatchVersion());
357 qgcApp()->showAppMessage(tr("Vehicle is not running latest stable firmware! Running %1, latest stable is %2.").arg(currentVersionNumber, version));
358 }
359}
360
361int FirmwarePlugin::versionCompare(const Vehicle *vehicle, int major, int minor, int patch) const
362{
363 const int currMajor = vehicle->firmwareMajorVersion();
364 const int currMinor = vehicle->firmwareMinorVersion();
365 const int currPatch = vehicle->firmwarePatchVersion();
366
367 if ((currMajor == major) && (currMinor == minor) && (currPatch == patch)) {
368 return 0;
369 }
370
371 if ((currMajor > major)
372 || ((currMajor == major) && (currMinor > minor))
373 || ((currMajor == major) && (currMinor == minor) && (currPatch > patch)))
374 {
375 return 1;
376 }
377
378 return -1;
379}
380
381int FirmwarePlugin::versionCompare(const Vehicle *vehicle, const QString &compare) const
382{
383 const QStringList versionNumbers = compare.split(".");
384 if (versionNumbers.size() != 3) {
385 qCWarning(FirmwarePluginLog) << "Error parsing version number: wrong format";
386 return -1;
387 }
388
389 const int major = versionNumbers[0].toInt();
390 const int minor = versionNumbers[1].toInt();
391 const int patch = versionNumbers[2].toInt();
392
393 return versionCompare(vehicle, major, minor, patch);
394}
395
396void FirmwarePlugin::sendGCSMotionReport(Vehicle *vehicle, const FollowMe::GCSMotionReport &motionReport, uint8_t estimationCapabilities) const
397{
398 SharedLinkInterfacePtr sharedLink = vehicle->vehicleLinkManager()->primaryLink().lock();
399 if (!sharedLink) {
400 return;
401 }
402
403 mavlink_follow_target_t follow_target{};
404
405 follow_target.timestamp = qgcApp()->msecsSinceBoot();
406 follow_target.est_capabilities = estimationCapabilities;
407 follow_target.position_cov[0] = static_cast<float>(motionReport.pos_std_dev[0]);
408 follow_target.position_cov[2] = static_cast<float>(motionReport.pos_std_dev[2]);
409 follow_target.alt = static_cast<float>(motionReport.altMetersAMSL);
410 follow_target.lat = motionReport.lat_int;
411 follow_target.lon = motionReport.lon_int;
412 follow_target.vel[0] = static_cast<float>(motionReport.vxMetersPerSec);
413 follow_target.vel[1] = static_cast<float>(motionReport.vyMetersPerSec);
414
415 mavlink_message_t message{};
416 mavlink_msg_follow_target_encode_chan(
417 static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
418 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
419 sharedLink->mavlinkChannel(),
420 &message,
421 &follow_target
422 );
423
424 (void) vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), message);
425}
426
428{
429 return new Autotune(vehicle);
430}
431
433{
434 _flightModeList.clear();
435 _modeEnumToString.clear();
436
437 for (FirmwareFlightMode &flightMode : flightModeList) {
438 _modeEnumToString[flightMode.custom_mode] = flightMode.mode_name;
440 }
441
443 qCDebug(FirmwarePluginLog) << "Flight Mode:" << flightMode.mode_name << " Custom Mode:" << flightMode.custom_mode;
444 }
445}
446
448{
449 for (const FirmwareFlightMode &existingFlightMode : _flightModeList) {
450 if (existingFlightMode.custom_mode == newFlightMode.custom_mode) {
451 qCDebug(FirmwarePluginLog) << "Flight Mode:" << newFlightMode.mode_name << " Custom Mode:" << newFlightMode.custom_mode
452 << " already exists, not adding again.";
453 return;
454 }
455 }
456 _flightModeList += newFlightMode;
457}
458
459/*===========================================================================*/
460
static const QString guided_mode_not_supported_by_vehicle
QList< FirmwareFlightMode > FlightModeList
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
#define qgcApp()
struct __mavlink_message mavlink_message_t
Unified file download utility with decompression, verification, and QML support.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
virtual CommandSupportedResult anyVersionSupportsCommand(MAV_CMD) const
CommandSupportedResult getCommandSupported(MAV_CMD cmd) const
virtual void guidedModeChangeEquivalentAirspeedMetersSecond(Vehicle *vehicle, double airspeed_equiv) const
virtual void guidedModeChangeAltitude(Vehicle *vehicle, double altitudeChange, bool pauseVehicle)
virtual void startMission(Vehicle *vehicle) const
Command the vehicle to start the mission.
virtual void checkIfIsLatestStable(Vehicle *vehicle) const
Used to check if running firmware is latest stable version.
FlightModeList _flightModeList
virtual const QVariantList & toolIndicators(const Vehicle *vehicle)
virtual void guidedModeChangeGroundSpeedMetersSecond(Vehicle *vehicle, double groundspeed) const
virtual bool setFlightMode(const QString &flightMode, uint8_t *base_mode, uint32_t *custom_mode) const
virtual ~FirmwarePlugin()
virtual void guidedModeTakeoff(Vehicle *vehicle, double takeoffAltRel) const
Command vehicle to takeoff from current location to the specified height.
bool _setFlightModeAndValidate(Vehicle *vehicle, const QString &flightMode) const
virtual QString _getLatestVersionFileUrl(Vehicle *) const
returns url with latest firmware release information.
void _updateFlightModeList(FlightModeList &flightModeList)
virtual void guidedModeChangeHeading(Vehicle *vehicle, const QGeoCoordinate &headingCoord) const
Command vehicle to rotate towards specified location.
virtual QString flightMode(uint8_t base_mode, uint32_t custom_mode) const
virtual void startTakeoff(Vehicle *vehicle) const
Command the vehicle to start a takeoff.
void _addNewFlightMode(FirmwareFlightMode &flightMode)
virtual void pauseVehicle(Vehicle *vehicle) const
int versionCompare(const Vehicle *vehicle, const QString &compare) const
virtual Autotune * createAutotune(Vehicle *vehicle) const
Creates Autotune object.
virtual AutoPilotPlugin * autopilotPlugin(Vehicle *vehicle) const
virtual void guidedModeRTL(Vehicle *vehicle, bool smartRTL) const
Command vehicle to return to launch.
virtual QString _versionRegex() const
Returns regex QString to extract version information from text.
virtual void _getParameterMetaDataVersionInfo(const QString &metaDataFile, int &majorVersion, int &minorVersion) const
virtual MavlinkCameraControl * createCameraControl(const mavlink_camera_information_t *info, Vehicle *vehicle, int compID, QObject *parent=nullptr) const
Camera control.
bool _armVehicleAndValidate(Vehicle *vehicle) const
QVariantList _toolIndicatorList
virtual void setGuidedMode(Vehicle *vehicle, bool guidedMode) const
Set guided flight mode.
virtual void guidedModeGotoLocation(Vehicle *vehicle, const QGeoCoordinate &gotoCoord, double forwardFlightLoiterRadius=0.0) const
Command vehicle to move to specified location (altitude is included and relative)
FlightModeCustomModeMap _modeEnumToString
virtual QString missionCommandOverrides(QGCMAVLink::VehicleClass_t vehicleClass) const
virtual void batteryConsumptionData(Vehicle *vehicle, int &mAhBattery, double &hoverAmps, double &cruiseAmps) const
virtual QGCCameraManager * createCameraManager(Vehicle *vehicle) const
Creates vehicle camera manager.
virtual void sendGCSMotionReport(Vehicle *vehicle, const FollowMe::GCSMotionReport &motionReport, uint8_t estimationCapabilities) const
Sends the appropriate mavlink message for follow me support.
QMap< int, remapParamNameMinorVersionRemapMap_t > remapParamNameMajorVersionMap_t
virtual const remapParamNameMajorVersionMap_t & paramNameRemapMajorVersionMap() const
Returns the mapping structure which is used to map from one parameter name to another based on firmwa...
virtual void guidedModeLand(Vehicle *vehicle) const
Command vehicle to land at current location.
virtual bool hasGimbal(Vehicle *vehicle, bool &rollSupported, bool &pitchSupported, bool &yawSupported) const
virtual void _versionFileDownloadFinished(const QString &remoteFile, const QString &localFile, const Vehicle *vehicle) const
Callback to process file with latest release information.
static int getComponentId()
Get the component id of this application.
static MAVLinkProtocol * instance()
Abstract base class for all camera controls: real and simulated.
Camera Manager.
void finished(bool success, const QString &localPath, const QString &errorMessage)
bool start(const QString &remoteUrl)
MAVLink Camera API controller - connected to a real mavlink v2 camera.
WeakLinkInterfacePtr primaryLink() const
QString flightMode() const
Definition Vehicle.cc:1549
VehicleLinkManager * vehicleLinkManager()
Definition Vehicle.h:580
int firmwareMinorVersion() const
Definition Vehicle.h:691
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
Definition Vehicle.cc:1470
void setFlightMode(const QString &flightMode)
Definition Vehicle.cc:1559
int firmwareVersionType() const
Definition Vehicle.h:693
int firmwarePatchVersion() const
Definition Vehicle.h:692
bool armed() const
Definition Vehicle.h:449
int versionCompare(const QString &compare) const
Used to check if running current version is equal or higher than the one being compared.
Definition Vehicle.cc:3646
int firmwareMajorVersion() const
Definition Vehicle.h:690
void setArmed(bool armed, bool showError)
Definition Vehicle.cc:1520