地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

921 lines
33 KiB

/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "FirmwarePlugin.h"
#include "QGCApplication.h"
#include "Generic/GenericAutoPilotPlugin.h"
#include "CameraMetaData.h"
#include "SettingsManager.h"
#include "AppSettings.h"
#include "QGCFileDownload.h"
#include "QGCCameraManager.h"
#include <QRegularExpression>
#include <QDebug>
QGC_LOGGING_CATEGORY(FirmwarePluginLog, "FirmwarePluginLog")
static FirmwarePluginFactoryRegister* _instance = nullptr;
const QString guided_mode_not_supported_by_vehicle = QObject::tr("Guided mode not supported by Vehicle.");
QVariantList FirmwarePlugin::_cameraList;
const QString FirmwarePlugin::px4FollowMeFlightMode(QObject::tr("Follow Me"));
FirmwarePluginFactory::FirmwarePluginFactory(void)
{
FirmwarePluginFactoryRegister::instance()->registerPluginFactory(this);
}
QList<QGCMAVLink::VehicleClass_t> FirmwarePluginFactory::supportedVehicleClasses(void) const
{
return QGCMAVLink::allVehicleClasses();
}
FirmwarePluginFactoryRegister* FirmwarePluginFactoryRegister::instance(void)
{
if (!_instance) {
_instance = new FirmwarePluginFactoryRegister;
}
return _instance;
}
AutoPilotPlugin* FirmwarePlugin::autopilotPlugin(Vehicle* vehicle)
{
return new GenericAutoPilotPlugin(vehicle, vehicle);
}
bool FirmwarePlugin::isCapable(const Vehicle *vehicle, FirmwareCapabilities capabilities)
{
Q_UNUSED(vehicle);
Q_UNUSED(capabilities);
return false;
}
QList<VehicleComponent*> FirmwarePlugin::componentsForVehicle(AutoPilotPlugin* vehicle)
{
Q_UNUSED(vehicle);
return QList<VehicleComponent*>();
}
QString FirmwarePlugin::flightMode(uint8_t base_mode, uint32_t custom_mode) const
{
QString flightMode;
struct Bit2Name {
uint8_t baseModeBit;
const char* name;
};
static const struct Bit2Name rgBit2Name[] = {
{ MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, "Manual" },
{ MAV_MODE_FLAG_STABILIZE_ENABLED, "Stabilize" },
{ MAV_MODE_FLAG_GUIDED_ENABLED, "Guided" },
{ MAV_MODE_FLAG_AUTO_ENABLED, "Auto" },
{ MAV_MODE_FLAG_TEST_ENABLED, "Test" },
};
Q_UNUSED(custom_mode);
if (base_mode == 0) {
flightMode = "PreFlight";
} else if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
flightMode = QString("Custom:0x%1").arg(custom_mode, 0, 16);
} else {
for (size_t i=0; i<sizeof(rgBit2Name)/sizeof(rgBit2Name[0]); i++) {
if (base_mode & rgBit2Name[i].baseModeBit) {
if (i != 0) {
flightMode += " ";
}
flightMode += rgBit2Name[i].name;
}
}
}
return flightMode;
}
bool FirmwarePlugin::setFlightMode(const QString& flightMode, uint8_t* base_mode, uint32_t* custom_mode)
{
Q_UNUSED(flightMode);
Q_UNUSED(base_mode);
Q_UNUSED(custom_mode);
qWarning() << "FirmwarePlugin::setFlightMode called on base class, not supported";
return false;
}
int FirmwarePlugin::defaultJoystickTXMode(void)
{
return 2;
}
bool FirmwarePlugin::supportsThrottleModeCenterZero(void)
{
// By default, this is supported
return true;
}
bool FirmwarePlugin::supportsNegativeThrust(Vehicle* /*vehicle*/)
{
// By default, this is not supported
return false;
}
bool FirmwarePlugin::supportsRadio(void)
{
return true;
}
bool FirmwarePlugin::supportsMotorInterference(void)
{
return true;
}
bool FirmwarePlugin::supportsJSButton(void)
{
return false;
}
bool FirmwarePlugin::adjustIncomingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message)
{
Q_UNUSED(vehicle);
Q_UNUSED(message);
// Generic plugin does no message adjustment
return true;
}
void FirmwarePlugin::adjustOutgoingMavlinkMessageThreadSafe(Vehicle* /*vehicle*/, LinkInterface* /*outgoingLink*/, mavlink_message_t* /*message*/)
{
// Generic plugin does no message adjustment
}
void FirmwarePlugin::initializeVehicle(Vehicle* vehicle)
{
Q_UNUSED(vehicle);
// Generic Flight Stack is by definition "generic", so no extra work
}
bool FirmwarePlugin::sendHomePositionToVehicle(void)
{
// Generic stack does not want home position sent in the first position.
// Subsequent sequence numbers must be adjusted.
// This is the mavlink spec default.
return false;
}
QList<MAV_CMD> FirmwarePlugin::supportedMissionCommands(QGCMAVLink::VehicleClass_t vehicleClass)
{
// Generic supports all commands
return QList<MAV_CMD>();
}
QString FirmwarePlugin::missionCommandOverrides(QGCMAVLink::VehicleClass_t vehicleClass) const
{
switch (vehicleClass) {
case QGCMAVLink::VehicleClassGeneric:
return QStringLiteral(":/json/MavCmdInfoCommon.json");
case QGCMAVLink::VehicleClassFixedWing:
return QStringLiteral(":/json/MavCmdInfoFixedWing.json");
case QGCMAVLink::VehicleClassMultiRotor:
return QStringLiteral(":/json/MavCmdInfoMultiRotor.json");
case QGCMAVLink::VehicleClassVTOL:
return QStringLiteral(":/json/MavCmdInfoVTOL.json");
case QGCMAVLink::VehicleClassSub:
return QStringLiteral(":/json/MavCmdInfoSub.json");
case QGCMAVLink::VehicleClassRoverBoat:
return QStringLiteral(":/json/MavCmdInfoRover.json");
default:
qWarning() << "FirmwarePlugin::missionCommandOverrides called with bad VehicleClass_t:" << vehicleClass;
return QString();
}
}
void FirmwarePlugin::_getParameterMetaDataVersionInfo(const QString& metaDataFile, int& majorVersion, int& minorVersion)
{
Q_UNUSED(metaDataFile);
majorVersion = -1;
minorVersion = -1;
}
bool FirmwarePlugin::isGuidedMode(const Vehicle* vehicle) const
{
// Not supported by generic vehicle
Q_UNUSED(vehicle);
return false;
}
void FirmwarePlugin::setGuidedMode(Vehicle* vehicle, bool guidedMode)
{
Q_UNUSED(vehicle);
Q_UNUSED(guidedMode);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::pauseVehicle(Vehicle* vehicle)
{
// Not supported by generic vehicle
Q_UNUSED(vehicle);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::guidedModeRTL(Vehicle* vehicle, bool smartRTL)
{
// Not supported by generic vehicle
Q_UNUSED(vehicle);
Q_UNUSED(smartRTL);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::guidedModeLand(Vehicle* vehicle)
{
// Not supported by generic vehicle
Q_UNUSED(vehicle);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::guidedModeTakeoff(Vehicle* vehicle, double takeoffAltRel)
{
// Not supported by generic vehicle
Q_UNUSED(vehicle);
Q_UNUSED(takeoffAltRel);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::guidedModeGotoLocation(Vehicle* vehicle, const QGeoCoordinate& gotoCoord)
{
// Not supported by generic vehicle
Q_UNUSED(vehicle);
Q_UNUSED(gotoCoord);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::guidedModeChangeAltitude(Vehicle*, double)
{
// Not supported by generic vehicle
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
void FirmwarePlugin::startMission(Vehicle*)
{
// Not supported by generic vehicle
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}
const FirmwarePlugin::remapParamNameMajorVersionMap_t& FirmwarePlugin::paramNameRemapMajorVersionMap(void) const
{
static const remapParamNameMajorVersionMap_t remap;
return remap;
}
int FirmwarePlugin::remapParamNameHigestMinorVersionNumber(int) const
{
return 0;
}
QString FirmwarePlugin::vehicleImageOpaque(const Vehicle*) const
{
return QStringLiteral("/qmlimages/vehicleArrowOpaque.svg");
}
QString FirmwarePlugin::vehicleImageOutline(const Vehicle*) const
{
return QStringLiteral("/qmlimages/vehicleArrowOutline.svg");
}
QString FirmwarePlugin::vehicleImageCompass(const Vehicle*) const
{
return QStringLiteral("/qmlimages/compassInstrumentArrow.svg");
}
const QVariantList& FirmwarePlugin::toolIndicators(const Vehicle*)
{
//-- Default list of indicators for all vehicles.
if(_toolIndicatorList.size() == 0) {
_toolIndicatorList = QVariantList({
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/MessageIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/GPSIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/TelemetryRSSIIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/RCRSSIIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/BatteryIndicator.qml")),
});
}
return _toolIndicatorList;
}
const QVariantList& FirmwarePlugin::modeIndicators(const Vehicle*)
{
//-- Default list of indicators for all vehicles.
if(_modeIndicatorList.size() == 0) {
_modeIndicatorList = QVariantList({
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/ROIIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/ArmedIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/ModeIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/VTOLModeIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/MultiVehicleSelector.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/toolbar/LinkIndicator.qml")),
});
}
return _modeIndicatorList;
}
const QVariantList& FirmwarePlugin::cameraList(const Vehicle*)
{
if (_cameraList.size() == 0) {
CameraMetaData* metaData;
metaData = new CameraMetaData(
//tr("Canon S100 @ 5.2mm f/2"),
tr("Canon S100 PowerShot"),
7.6, // sensorWidth
5.7, // sensorHeight
4000, // imageWidth
3000, // imageHeight
5.2, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Canon EOS-M 22mm f/2"),
tr("Canon EOS-M 22mm"),
22.3, // sensorWidth
14.9, // sensorHeight
5184, // imageWidth
3456, // imageHeight
22, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Canon G9X @ 10.2mm f/2"),
tr("Canon G9 X PowerShot"),
13.2, // sensorWidth
8.8, // sensorHeight
5488, // imageWidth
3680, // imageHeight
10.2, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Canon SX260 HS @ 4.5mm f/3.5"),
tr("Canon SX260 HS PowerShot"),
6.17, // sensorWidth
4.55, // sensorHeight
4000, // imageWidth
3000, // imageHeight
4.5, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("GoPro Hero 4"),
6.17, // sensorWidth
4.55, // sendsorHeight
4000, // imageWidth
3000, // imageHeight
2.98, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Parrot Sequoia RGB"),
tr("Parrot Sequioa RGB"),
6.17, // sensorWidth
4.63, // sendsorHeight
4608, // imageWidth
3456, // imageHeight
4.9, // focalLength
true, // landscape
false, // fixedOrientation
1, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Parrot Sequoia Monochrome"),
tr("Parrot Sequioa Monochrome"),
4.8, // sensorWidth
3.6, // sendsorHeight
1280, // imageWidth
960, // imageHeight
4.0, // focalLength
true, // landscape
false, // fixedOrientation
0.8, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("RedEdge"),
4.8, // sensorWidth
3.6, // sendsorHeight
1280, // imageWidth
960, // imageHeight
5.5, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Ricoh GR II 18.3mm f/2.8"),
tr("Ricoh GR II"),
23.7, // sensorWidth
15.7, // sendsorHeight
4928, // imageWidth
3264, // imageHeight
18.3, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sentera Double 4K Sensor"),
6.2, // sensorWidth
4.65, // sendsorHeight
4000, // imageWidth
3000, // imageHeight
5.4, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sentera NDVI Single Sensor"),
4.68, // sensorWidth
3.56, // sendsorHeight
1248, // imageWidth
952, // imageHeight
4.14, // focalLength
true, // landscape
false, // fixedOrientation
0, // minTriggerInterval
this);
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//-- http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-6000-body-kit#product_details_default
//tr("Sony a6000 Sony 16mm f/2.8"),
tr("Sony a6000 16mm"),
23.5, // sensorWidth
15.6, // sensorHeight
6000, // imageWidth
4000, // imageHeight
16, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
2.0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sony a6300 Zeiss 21mm f/2.8"),
23.5, // sensorWidth
15.6, // sensorHeight
6000, // imageWidth
4000, // imageHeight
21, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
2.0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sony a6300 Sony 28mm f/2.0"),
23.5, // sensorWidth
15.6, // sensorHeight
6000, // imageWidth
4000, // imageHeight
28, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
2.0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sony a7R II Zeiss 21mm f/2.8"),
35.814, // sensorWidth
23.876, // sensorHeight
7952, // imageWidth
5304, // imageHeight
21, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
2.0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sony a7R II Sony 28mm f/2.0"),
35.814, // sensorWidth
23.876, // sensorHeight
7952, // imageWidth
5304, // imageHeight
28, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
2.0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sony DSC-QX30U @ 4.3mm f/3.5"),
7.82, // sensorWidth
5.865, // sensorHeight
5184, // imageWidth
3888, // imageHeight
4.3, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
2.0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Sony DSC-RX0"),
13.2, // sensorWidth
8.8, // sensorHeight
4800, // imageWidth
3200, // imageHeight
7.7, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//-- http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications
//-- http://www.sony.com/electronics/camera-lenses/sel16f28/specifications
//tr("Sony ILCE-QX1 Sony 16mm f/2.8"),
tr("Sony ILCE-QX1"),
23.2, // sensorWidth
15.4, // sensorHeight
5456, // imageWidth
3632, // imageHeight
16, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//-- http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications
//tr("Sony NEX-5R Sony 20mm f/2.8"),
tr("Sony NEX-5R 20mm"),
23.2, // sensorWidth
15.4, // sensorHeight
4912, // imageWidth
3264, // imageHeight
20, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
1, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
//tr("Sony RX100 II @ 10.4mm f/1.8"),
tr("Sony RX100 II 28mm"),
13.2, // sensorWidth
8.8, // sensorHeight
5472, // imageWidth
3648, // imageHeight
10.4, // focalLength
true, // true: landscape orientation
false, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Yuneec CGOET"),
5.6405, // sensorWidth
3.1813, // sensorHeight
1920, // imageWidth
1080, // imageHeight
3.5, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
1.3, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Yuneec E10T"),
5.6405, // sensorWidth
3.1813, // sensorHeight
1920, // imageWidth
1080, // imageHeight
23, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
1.3, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Yuneec E50"),
6.2372, // sensorWidth
4.7058, // sensorHeight
4000, // imageWidth
3000, // imageHeight
7.2, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
1.3, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Yuneec E90"),
13.3056, // sensorWidth
8.656, // sensorHeight
5472, // imageWidth
3648, // imageHeight
8.29, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
1.3, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
metaData = new CameraMetaData(
tr("Flir Duo R"),
160, // sensorWidth
120, // sensorHeight
1920, // imageWidth
1080, // imageHeight
1.9, // focalLength
true, // true: landscape orientation
true, // true: camera is fixed orientation
0, // minimum trigger interval
this); // parent
_cameraList.append(QVariant::fromValue(metaData));
}
return _cameraList;
}
QMap<QString, FactGroup*>* FirmwarePlugin::factGroups(void) {
// Generic plugin has no FactGroups
return nullptr;
}
bool FirmwarePlugin::_armVehicleAndValidate(Vehicle* vehicle)
{
if (vehicle->armed()) {
return true;
}
bool armedChanged = false;
// We try arming 3 times
for (int retries=0; retries<3; retries++) {
vehicle->setArmed(true);
// Wait for vehicle to return armed state for 3 seconds
for (int i=0; i<30; i++) {
if (vehicle->armed()) {
armedChanged = true;
break;
}
QGC::SLEEP::msleep(100);
qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents);
}
if (armedChanged) {
break;
}
}
return armedChanged;
}
bool FirmwarePlugin::_setFlightModeAndValidate(Vehicle* vehicle, const QString& flightMode)
{
if (vehicle->flightMode() == flightMode) {
return true;
}
bool flightModeChanged = false;
// We try 3 times
for (int retries=0; retries<3; retries++) {
vehicle->setFlightMode(flightMode);
// Wait for vehicle to return flight mode
for (int i=0; i<13; i++) {
if (vehicle->flightMode() == flightMode) {
flightModeChanged = true;
break;
}
QGC::SLEEP::msleep(100);
qgcApp()->processEvents(QEventLoop::ExcludeUserInputEvents);
}
if (flightModeChanged) {
break;
}
}
return flightModeChanged;
}
void FirmwarePlugin::batteryConsumptionData(Vehicle* vehicle, int& mAhBattery, double& hoverAmps, double& cruiseAmps) const
{
Q_UNUSED(vehicle);
mAhBattery = 0;
hoverAmps = 0;
cruiseAmps = 0;
}
QString FirmwarePlugin::autoDisarmParameter(Vehicle* vehicle)
{
Q_UNUSED(vehicle);
return QString();
}
bool FirmwarePlugin::hasGimbal(Vehicle* vehicle, bool& rollSupported, bool& pitchSupported, bool& yawSupported)
{
Q_UNUSED(vehicle);
rollSupported = false;
pitchSupported = false;
yawSupported = false;
return false;
}
QGCCameraManager* FirmwarePlugin::createCameraManager(Vehicle* vehicle)
{
return new QGCCameraManager(vehicle);
}
QGCCameraControl* FirmwarePlugin::createCameraControl(const mavlink_camera_information_t *info, Vehicle *vehicle, int compID, QObject* parent)
{
return new QGCCameraControl(info, vehicle, compID, parent);
}
uint32_t FirmwarePlugin::highLatencyCustomModeTo32Bits(uint16_t hlCustomMode)
{
// Standard implementation assumes no special handling. Upper part of 32 bit value is not used.
return hlCustomMode;
}
void FirmwarePlugin::checkIfIsLatestStable(Vehicle* vehicle)
{
// This is required as mocklink uses a hardcoded firmware version
if (qgcApp()->runningUnitTests()) {
qCDebug(FirmwarePluginLog) << "Skipping version check";
return;
}
QString versionFile = _getLatestVersionFileUrl(vehicle);
qCDebug(FirmwarePluginLog) << "Downloading" << versionFile;
QGCFileDownload* downloader = new QGCFileDownload(this);
connect(
downloader,
&QGCFileDownload::downloadComplete,
this,
[vehicle, this](QString remoteFile, QString localFile, QString errorMsg) {
if (errorMsg.isEmpty()) {
_versionFileDownloadFinished(remoteFile, localFile, vehicle);
} else {
qCDebug(FirmwarePluginLog) << "Failed to download the latest fw version file. Error: " << errorMsg;
}
sender()->deleteLater();
});
downloader->download(versionFile);
}
void FirmwarePlugin::_versionFileDownloadFinished(QString& remoteFile, QString& localFile, Vehicle* vehicle)
{
qCDebug(FirmwarePluginLog) << "Download complete" << remoteFile << localFile;
// Now read the version file and pull out the version string
QFile versionFile(localFile);
if (!versionFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(FirmwarePluginLog) << "Error opening downloaded version file.";
return;
}
QTextStream stream(&versionFile);
QString versionFileContents = stream.readAll();
QString version;
QRegularExpressionMatch match = QRegularExpression(_versionRegex()).match(versionFileContents);
qCDebug(FirmwarePluginLog) << "Looking for version number...";
if (match.hasMatch()) {
version = match.captured(1);
} else {
qCWarning(FirmwarePluginLog) << "Unable to parse version info from file" << remoteFile;
return;
}
qCDebug(FirmwarePluginLog) << "Latest stable version = " << version;
int currType = vehicle->firmwareVersionType();
// Check if lower version than stable or same version but different type
if (currType == FIRMWARE_VERSION_TYPE_OFFICIAL && vehicle->versionCompare(version) < 0) {
QString currentVersionNumber = QString("%1.%2.%3").arg(vehicle->firmwareMajorVersion())
.arg(vehicle->firmwareMinorVersion())
.arg(vehicle->firmwarePatchVersion());
qgcApp()->showAppMessage(tr("Vehicle is not running latest stable firmware! Running %1, latest stable is %2.").arg(currentVersionNumber, version));
}
}
int FirmwarePlugin::versionCompare(Vehicle* vehicle, int major, int minor, int patch)
{
int currMajor = vehicle->firmwareMajorVersion();
int currMinor = vehicle->firmwareMinorVersion();
int currPatch = vehicle->firmwarePatchVersion();
if (currMajor == major && currMinor == minor && currPatch == patch) {
return 0;
}
if (currMajor > major
|| (currMajor == major && currMinor > minor)
|| (currMajor == major && currMinor == minor && currPatch > patch))
{
return 1;
}
return -1;
}
int FirmwarePlugin::versionCompare(Vehicle* vehicle, QString& compare)
{
QStringList versionNumbers = compare.split(".");
if(versionNumbers.size() != 3) {
qCWarning(FirmwarePluginLog) << "Error parsing version number: wrong format";
return -1;
}
int major = versionNumbers[0].toInt();
int minor = versionNumbers[1].toInt();
int patch = versionNumbers[2].toInt();
return versionCompare(vehicle, major, minor, patch);
}
QString FirmwarePlugin::gotoFlightMode(void) const
{
return QString();
}
void FirmwarePlugin::sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimationCapabilities)
{
MAVLinkProtocol* mavlinkProtocol = qgcApp()->toolbox()->mavlinkProtocol();
mavlink_follow_target_t follow_target = {};
follow_target.timestamp = qgcApp()->msecsSinceBoot();
follow_target.est_capabilities = estimationCapabilities;
follow_target.position_cov[0] = static_cast<float>(motionReport.pos_std_dev[0]);
follow_target.position_cov[2] = static_cast<float>(motionReport.pos_std_dev[2]);
follow_target.alt = static_cast<float>(motionReport.altMetersAMSL);
follow_target.lat = motionReport.lat_int;
follow_target.lon = motionReport.lon_int;
follow_target.vel[0] = static_cast<float>(motionReport.vxMetersPerSec);
follow_target.vel[1] = static_cast<float>(motionReport.vyMetersPerSec);
mavlink_message_t message;
mavlink_msg_follow_target_encode_chan(static_cast<uint8_t>(mavlinkProtocol->getSystemId()),
static_cast<uint8_t>(mavlinkProtocol->getComponentId()),
vehicle->priorityLink()->mavlinkChannel(),
&message,
&follow_target);
vehicle->sendMessageOnLinkThreadSafe(vehicle->priorityLink(), message);
}