Skip to content
Vehicle.cc 149 KiB
Newer Older
    UASMessageHandler* pMh = _toolbox->uasMessageHandler();
    MessageType_t type = newCount ? _currentMessageType : MessageNone;
    int errorCount     = _currentErrorCount;
    int warnCount      = _currentWarningCount;
    int normalCount    = _currentNormalCount;
    //-- Add current message counts
    errorCount  += pMh->getErrorCount();
    warnCount   += pMh->getWarningCount();
    normalCount += pMh->getNormalCount();
    //-- See if we have a higher level
    if(errorCount != _currentErrorCount) {
        _currentErrorCount = errorCount;
        type = MessageError;
    }
    if(warnCount != _currentWarningCount) {
        _currentWarningCount = warnCount;
        if(_currentMessageType != MessageError) {
            type = MessageWarning;
        }
    }
    if(normalCount != _currentNormalCount) {
        _currentNormalCount = normalCount;
        if(_currentMessageType != MessageError && _currentMessageType != MessageWarning) {
            type = MessageNormal;
        }
    }
    int count = _currentErrorCount + _currentWarningCount + _currentNormalCount;
    if(count != _currentMessageCount) {
        _currentMessageCount = count;
        // Display current total new messages count
        emit newMessageCountChanged();
    }
    if(type != _currentMessageType) {
        _currentMessageType = type;
        // Update message level
        emit messageTypeChanged();
    }
    // Update message count (all messages)
    if(newCount != _messageCount) {
        _messageCount = newCount;
        emit messageCountChanged();
    }
    QString errMsg = pMh->getLatestError();
    if(errMsg != _latestError) {
        _latestError = errMsg;
        emit latestErrorChanged();
    }
}

void Vehicle::resetMessages()
{
    // Reset Counts
    int count = _currentMessageCount;
    MessageType_t type = _currentMessageType;
    _currentErrorCount   = 0;
    _currentWarningCount = 0;
    _currentNormalCount  = 0;
    _currentMessageCount = 0;
    _currentMessageType = MessageNone;
    if(count != _currentMessageCount) {
        emit newMessageCountChanged();
    }
    if(type != _currentMessageType) {
        emit messageTypeChanged();
    }
}
void Vehicle::_loadSettings()
    QSettings settings;
    settings.beginGroup(QString(_settingsGroup).arg(_id));
    // Joystick enabled is a global setting so first make sure there are any joysticks connected
    if (_toolbox->joystickManager()->joysticks().count()) {
        setJoystickEnabled(settings.value(_joystickEnabledSettingsKey, false).toBool());
void Vehicle::_saveSettings()
{
    QSettings settings;
    settings.beginGroup(QString(_settingsGroup).arg(_id));
    // The joystick enabled setting should only be changed if a joystick is present
    // since the checkbox can only be clicked if one is present
    if (_toolbox->joystickManager()->joysticks().count()) {
        settings.setValue(_joystickEnabledSettingsKey, _joystickEnabled);
    }
bool Vehicle::joystickEnabled()
{
    return _joystickEnabled;
}

void Vehicle::setJoystickEnabled(bool enabled)
{
    _startJoystick(_joystickEnabled);
    _saveSettings();
    emit joystickEnabledChanged(_joystickEnabled);
}

void Vehicle::_startJoystick(bool start)
{
    Joystick* joystick = _joystickManager->activeJoystick();
    if (joystick) {
        if (start) {
        } else {
            joystick->stopPolling();
        }
    }
}

bool Vehicle::active()
{
    return _active;
}

void Vehicle::setActive(bool active)
{
    if (_active != active) {
        _active = active;
        emit activeChanged(_active);
    }
QGeoCoordinate Vehicle::homePosition()
{
    return _homePosition;
}
Don Gagne's avatar
Don Gagne committed

void Vehicle::setArmed(bool armed)
{
    // We specifically use COMMAND_LONG:MAV_CMD_COMPONENT_ARM_DISARM since it is supported by more flight stacks.
    sendMavCommand(_defaultComponentId,
                   MAV_CMD_COMPONENT_ARM_DISARM,
                   true,    // show error if fails
                   armed ? 1.0f : 0.0f);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::forceArm(void)
{
    sendMavCommand(_defaultComponentId,
                   MAV_CMD_COMPONENT_ARM_DISARM,
                   true,    // show error if fails
                   1.0f,    // arm
                   2989);   // force arm
}

bool Vehicle::flightModeSetAvailable()
    return _firmwarePlugin->isCapable(this, FirmwarePlugin::SetFlightModeCapability);
QStringList Vehicle::flightModes()
Daniel Agar's avatar
Daniel Agar committed
    return _firmwarePlugin->flightModes(this);
QStringList Vehicle::extraJoystickFlightModes()
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
{
    return _firmwarePlugin->extraJoystickFlightModes(this);
}

QString Vehicle::flightMode() const
Don Gagne's avatar
Don Gagne committed
{
    return _firmwarePlugin->flightMode(_base_mode, _custom_mode);
}

void Vehicle::setFlightMode(const QString& flightMode)
{
    uint8_t     base_mode;
    uint32_t    custom_mode;

    if (_firmwarePlugin->setFlightMode(flightMode, &base_mode, &custom_mode)) {
        // setFlightMode will only set MAV_MODE_FLAG_CUSTOM_MODE_ENABLED in base_mode, we need to move back in the existing
        // states.
        uint8_t newBaseMode = _base_mode & ~MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE;
        newBaseMode |= base_mode;

        mavlink_message_t msg;
        mavlink_msg_set_mode_pack_chan(_mavlink->getSystemId(),
                                       _mavlink->getComponentId(),
                                       priorityLink()->mavlinkChannel(),
                                       &msg,
                                       id(),
                                       newBaseMode,
                                       custom_mode);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        sendMessageOnLinkThreadSafe(priorityLink(), msg);
Don Gagne's avatar
Don Gagne committed
    } else {
Don Gagne's avatar
Don Gagne committed
        qWarning() << "FirmwarePlugin::setFlightMode failed, flightMode:" << flightMode;
QString Vehicle::priorityLinkName() const
    if (_priorityLink) {
        return _priorityLink->getName();
QVariantList Vehicle::links() const {
    QVariantList ret;

    for( const auto &item: _links )
        ret << QVariant::fromValue(item);

    return ret;
}

void Vehicle::setPriorityLinkByName(const QString& priorityLinkName)
{
    if (priorityLinkName == _priorityLink->getName()) {
        // The link did not change
        return;
    }

    LinkInterface* newPriorityLink = nullptr;


    for (int i=0; i<_links.count(); i++) {
        if (_links[i]->getName() == priorityLinkName) {
            newPriorityLink = _links[i];
        }
    }

    if (newPriorityLink) {
        _priorityLink = _toolbox->linkManager()->sharedLinkInterfacePointerForLink(newPriorityLink);
        _updateHighLatencyLink(true);
        emit priorityLinkNameChanged(_priorityLink->getName());
        _linkActiveChanged(_priorityLink.data(), _priorityLink->link_active(_id), _id);
Don Gagne's avatar
Don Gagne committed
void Vehicle::requestDataStream(MAV_DATA_STREAM stream, uint16_t rate, bool sendMultiple)
{
    mavlink_message_t               msg;
    mavlink_request_data_stream_t   dataStream;
Don Gagne's avatar
Don Gagne committed
    memset(&dataStream, 0, sizeof(dataStream));

    dataStream.req_stream_id = stream;
    dataStream.req_message_rate = rate;
    dataStream.start_stop = 1;  // start
    dataStream.target_system = id();
    dataStream.target_component = _defaultComponentId;
    mavlink_msg_request_data_stream_encode_chan(_mavlink->getSystemId(),
                                                _mavlink->getComponentId(),
                                                priorityLink()->mavlinkChannel(),
                                                &msg,
                                                &dataStream);
Don Gagne's avatar
Don Gagne committed
    if (sendMultiple) {
        // We use sendMessageMultiple since we really want these to make it to the vehicle
        sendMessageMultiple(msg);
    } else {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        sendMessageOnLinkThreadSafe(priorityLink(), msg);
void Vehicle::_sendMessageMultipleNext()
{
    if (_nextSendMessageMultipleIndex < _sendMessageMultipleList.count()) {
        qCDebug(VehicleLog) << "_sendMessageMultipleNext:" << _sendMessageMultipleList[_nextSendMessageMultipleIndex].message.msgid;
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        sendMessageOnLinkThreadSafe(priorityLink(), _sendMessageMultipleList[_nextSendMessageMultipleIndex].message);
        if (--_sendMessageMultipleList[_nextSendMessageMultipleIndex].retryCount <= 0) {
            _sendMessageMultipleList.removeAt(_nextSendMessageMultipleIndex);
        } else {
            _nextSendMessageMultipleIndex++;
        }
    }
    if (_nextSendMessageMultipleIndex >= _sendMessageMultipleList.count()) {
        _nextSendMessageMultipleIndex = 0;
    }
}

void Vehicle::sendMessageMultiple(mavlink_message_t message)
{
    SendMessageMultipleInfo_t   info;
    info.message =      message;
    info.retryCount =   _sendMessageMultipleRetries;
    _sendMessageMultipleList.append(info);
}

void Vehicle::_missionManagerError(int errorCode, const QString& errorMsg)
{
    Q_UNUSED(errorCode);
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
    qgcApp()->showAppMessage(tr("Mission transfer failed. Error: %1").arg(errorMsg));
void Vehicle::_geoFenceManagerError(int errorCode, const QString& errorMsg)
{
    Q_UNUSED(errorCode);
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
    qgcApp()->showAppMessage(tr("GeoFence transfer failed. Error: %1").arg(errorMsg));
}

void Vehicle::_rallyPointManagerError(int errorCode, const QString& errorMsg)
{
    Q_UNUSED(errorCode);
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
    qgcApp()->showAppMessage(tr("Rally Point transfer failed. Error: %1").arg(errorMsg));
void Vehicle::_clearCameraTriggerPoints()
{
    _cameraTriggerPoints.clearAndDeleteContents();
void Vehicle::_flightTimerStart()
    _flightTimer.start();
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _flightTimeUpdater.start();
    _flightDistanceFact.setRawValue(0);
    _flightTimeFact.setRawValue(0);
void Vehicle::_flightTimerStop()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
{
    _flightTimeUpdater.stop();
}

void Vehicle::_updateFlightTime()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
{
    _flightTimeFact.setRawValue((double)_flightTimer.elapsed() / 1000.0);
}

DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::_firstMissionLoadComplete()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    disconnect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_firstMissionLoadComplete);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _initialConnectStateMachine->advance();
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::_firstGeoFenceLoadComplete()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    disconnect(_geoFenceManager, &GeoFenceManager::loadComplete,   this, &Vehicle::_firstGeoFenceLoadComplete);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _initialConnectStateMachine->advance();
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::_firstRallyPointLoadComplete()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    disconnect(_rallyPointManager, &RallyPointManager::loadComplete,   this, &Vehicle::_firstRallyPointLoadComplete);
    _initialPlanRequestComplete = true;
    emit initialPlanRequestCompleteChanged(true);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _initialConnectStateMachine->advance();
void Vehicle::_parametersReady(bool parametersReady)
{
Don Gagne's avatar
 
Don Gagne committed
    qDebug() << "_parametersReady" << parametersReady;
DonLakeFlyer's avatar
 
DonLakeFlyer committed

    // Try to set current unix time to the vehicle
    _sendQGCTimeToVehicle();
    // Send time twice, more likely to get to the vehicle on a noisy link
    _sendQGCTimeToVehicle();
    if (parametersReady) {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        disconnect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady);
        _setupAutoDisarmSignalling();
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        _initialConnectStateMachine->advance();
Lorenz Meier's avatar
Lorenz Meier committed
    }
void Vehicle::_sendQGCTimeToVehicle()
{
    mavlink_message_t       msg;
    mavlink_system_time_t   cmd;

    // Timestamp of the master clock in microseconds since UNIX epoch.
    cmd.time_unix_usec = QDateTime::currentDateTime().currentMSecsSinceEpoch()*1000;
    // Timestamp of the component clock since boot time in milliseconds (Not necessary).
    cmd.time_boot_ms = 0;
    mavlink_msg_system_time_encode_chan(_mavlink->getSystemId(),
                                        _mavlink->getComponentId(),
                                        priorityLink()->mavlinkChannel(),
                                        &msg,
                                        &cmd);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    sendMessageOnLinkThreadSafe(priorityLink(), msg);
void Vehicle::disconnectInactiveVehicle()
Don Gagne's avatar
Don Gagne committed
    // Vehicle is no longer communicating with us, disconnect all links
    LinkManager* linkMgr = _toolbox->linkManager();
    for (int i=0; i<_links.count(); i++) {
        // FIXME: This linkInUse check is a hack fix for multiple vehicles on the same link.
        // The real fix requires significant restructuring which will come later.
        if (!_toolbox->multiVehicleManager()->linkInUse(_links[i], this)) {
            linkMgr->disconnectLink(_links[i]);
        }
    emit linksChanged();
dogmaphobic's avatar
dogmaphobic committed
void Vehicle::_imageReady(UASInterface*)
{
    if(_uas)
    {
        QImage img = _uas->getImage();
        _toolbox->imageProvider()->setImage(&img, _id);
dogmaphobic's avatar
dogmaphobic committed
        _flowImageIndex++;
        emit flowImageIndexChanged();
    }
}
Don Gagne's avatar
Don Gagne committed

void Vehicle::_remoteControlRSSIChanged(uint8_t rssi)
{
    //-- 0 <= rssi <= 100 - 255 means "invalid/unknown"
    if(rssi > 100) { // Anything over 100 doesn't make sense
        if(_rcRSSI != 255) {
            _rcRSSI = 255;
            emit rcRSSIChanged(_rcRSSI);
        }
        return;
    }
    //-- Initialize it
    if(_rcRSSIstore == 255.) {
        _rcRSSIstore = (double)rssi;
Don Gagne's avatar
Don Gagne committed
    // Low pass to git rid of jitter
    _rcRSSIstore = (_rcRSSIstore * 0.9f) + ((float)rssi * 0.1);
    uint8_t filteredRSSI = (uint8_t)ceil(_rcRSSIstore);
    if(_rcRSSIstore < 0.1) {
        filteredRSSI = 0;
    }
    if(_rcRSSI != filteredRSSI) {
        _rcRSSI = filteredRSSI;
        emit rcRSSIChanged(_rcRSSI);
    }
}
Gus Grubba's avatar
Gus Grubba committed
void Vehicle::virtualTabletJoystickValue(double roll, double pitch, double yaw, double thrust)
Don Gagne's avatar
Don Gagne committed
{
    // The following if statement prevents the virtualTabletJoystick from sending values if the standard joystick is enabled
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    if (!_joystickEnabled) {
        sendJoystickDataThreadSafe(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    static_cast<float>(roll),
                    static_cast<float>(pitch),
                    static_cast<float>(yaw),
                    static_cast<float>(thrust),
                    0);
Don Gagne's avatar
Don Gagne committed
}

void Vehicle::setConnectionLostEnabled(bool connectionLostEnabled)
{
    if (_connectionLostEnabled != connectionLostEnabled) {
        _connectionLostEnabled = connectionLostEnabled;
        emit connectionLostEnabledChanged(_connectionLostEnabled);
    }
}

void Vehicle::_linkActiveChanged(LinkInterface *link, bool active, int vehicleID)
    // only continue if the vehicle id is correct
    if (vehicleID != _id) {
    emit linksPropertiesChanged();
    bool communicationLost = false;
    bool communicationRegained = false;

    if (link == _priorityLink) {
        if (active && _connectionLost) {
            // communication to priority link regained
            _connectionLost = false;
            communicationRegained = true;
            emit connectionLostChanged(false);
            if (_priorityLink->highLatency()) {
                _setMaxProtoVersion(100);
        } else if (!active && !_connectionLost) {
            _updatePriorityLink(false /* updateActive */, false /* sendCommand */);
            if (link == _priorityLink) {
Don Gagne's avatar
 
Don Gagne committed
                // No other link to switch to was found, notify user of comm lossf
                _connectionLost = true;
                communicationLost = true;
                _heardFrom = false;
                emit connectionLostChanged(true);

                if (_autoDisconnect) {
                    // Reset link state
                    for (int i = 0; i < _links.length(); i++) {
                        _mavlink->resetMetadataForLink(_links.at(i));

                    disconnectInactiveVehicle();
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage((tr("%1 communication to auxiliary link %2 %3")).arg(_vehicleIdSpeech()).arg(link->getName()).arg(active ? "regained" : "lost"));
acfloria's avatar
acfloria committed
        _updatePriorityLink(false /* updateActive */, true /* sendCommand */);

    QString commSpeech;
    bool multiVehicle = _toolbox->multiVehicleManager()->vehicles()->count() > 1;
    if (communicationRegained) {
        commSpeech = tr("Communication regained");
        if (_links.count() > 1) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
            qgcApp()->showAppMessage(tr("Communication regained to vehicle %1 on %2 link %3").arg(_id).arg(_links.count() > 1 ? tr("priority") : tr("auxiliary")).arg(link->getName()));
        } else if (multiVehicle) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
            qgcApp()->showAppMessage(tr("Communication regained to vehicle %1").arg(_id));
        }
    }
    if (communicationLost) {
        commSpeech = tr("Communication lost");
        if (_links.count() > 1) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
            qgcApp()->showAppMessage(tr("Communication lost to vehicle %1 on %2 link %3").arg(_id).arg(_links.count() > 1 ? tr("priority") : tr("auxiliary")).arg(link->getName()));
        } else if (multiVehicle) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
            qgcApp()->showAppMessage(tr("Communication lost to vehicle %1").arg(_id));
        }
    }
    if (multiVehicle && (communicationLost || communicationRegained)) {
        commSpeech.append(tr(" to vehicle %1").arg(_id));
    }
    if (!commSpeech.isEmpty()) {
        _say(commSpeech);
    }
void Vehicle::_say(const QString& text)
    _toolbox->audioOutput()->say(text.toLower());
bool Vehicle::fixedWing() const
    return QGCMAVLink::isFixedWing(vehicleType());
bool Vehicle::rover() const
Don Gagne's avatar
Don Gagne committed
{
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    return QGCMAVLink::isRoverBoat(vehicleType());
Don Gagne's avatar
Don Gagne committed
}

bool Vehicle::sub() const
    return QGCMAVLink::isSub(vehicleType());
bool Vehicle::multiRotor() const
    return QGCMAVLink::isMultiRotor(vehicleType());
bool Vehicle::vtol() const
Don Gagne's avatar
Don Gagne committed
{
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    return QGCMAVLink::isVTOL(vehicleType());
Don Gagne's avatar
Don Gagne committed
}

bool Vehicle::supportsThrottleModeCenterZero() const
{
    return _firmwarePlugin->supportsThrottleModeCenterZero();
}

bool Vehicle::supportsNegativeThrust()
    return _firmwarePlugin->supportsNegativeThrust(this);
bool Vehicle::supportsRadio() const
{
    return _firmwarePlugin->supportsRadio();
}

bool Vehicle::supportsJSButton() const
{
    return _firmwarePlugin->supportsJSButton();
}

bool Vehicle::supportsMotorInterference() const
Jacob Walser's avatar
Jacob Walser committed
{
    return _firmwarePlugin->supportsMotorInterference();
}

bool Vehicle::supportsTerrainFrame() const
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    return !px4Firmware();
QString Vehicle::vehicleTypeName() const {
    static QMap<int, QString> typeNames = {
        { MAV_TYPE_GENERIC,         tr("Generic micro air vehicle" )},
        { MAV_TYPE_FIXED_WING,      tr("Fixed wing aircraft")},
        { MAV_TYPE_QUADROTOR,       tr("Quadrotor")},
        { MAV_TYPE_COAXIAL,         tr("Coaxial helicopter")},
        { MAV_TYPE_HELICOPTER,      tr("Normal helicopter with tail rotor.")},
        { MAV_TYPE_ANTENNA_TRACKER, tr("Ground installation")},
        { MAV_TYPE_GCS,             tr("Operator control unit / ground control station")},
        { MAV_TYPE_AIRSHIP,         tr("Airship, controlled")},
        { MAV_TYPE_FREE_BALLOON,    tr("Free balloon, uncontrolled")},
        { MAV_TYPE_ROCKET,          tr("Rocket")},
        { MAV_TYPE_GROUND_ROVER,    tr("Ground rover")},
        { MAV_TYPE_SURFACE_BOAT,    tr("Surface vessel, boat, ship")},
        { MAV_TYPE_SUBMARINE,       tr("Submarine")},
        { MAV_TYPE_HEXAROTOR,       tr("Hexarotor")},
        { MAV_TYPE_OCTOROTOR,       tr("Octorotor")},
        { MAV_TYPE_TRICOPTER,       tr("Octorotor")},
        { MAV_TYPE_FLAPPING_WING,   tr("Flapping wing")},
        { MAV_TYPE_KITE,            tr("Flapping wing")},
        { MAV_TYPE_ONBOARD_CONTROLLER, tr("Onboard companion controller")},
        { MAV_TYPE_VTOL_DUOROTOR,   tr("Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter")},
        { MAV_TYPE_VTOL_QUADROTOR,  tr("Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter")},
        { MAV_TYPE_VTOL_TILTROTOR,  tr("Tiltrotor VTOL")},
        { MAV_TYPE_VTOL_RESERVED2,  tr("VTOL reserved 2")},
        { MAV_TYPE_VTOL_RESERVED3,  tr("VTOL reserved 3")},
        { MAV_TYPE_VTOL_RESERVED4,  tr("VTOL reserved 4")},
        { MAV_TYPE_VTOL_RESERVED5,  tr("VTOL reserved 5")},
        { MAV_TYPE_GIMBAL,          tr("Onboard gimbal")},
        { MAV_TYPE_ADSB,            tr("Onboard ADSB peripheral")},
    };
    return typeNames[_vehicleType];
}

/// Returns the string to speak to identify the vehicle
QString Vehicle::_vehicleIdSpeech()
    if (_toolbox->multiVehicleManager()->vehicles()->count() > 1) {
        return tr("vehicle %1").arg(id());
    } else {
        return QString();
Don Gagne's avatar
Don Gagne committed
void Vehicle::_handleFlightModeChanged(const QString& flightMode)
    _say(tr("%1 %2 flight mode").arg(_vehicleIdSpeech()).arg(flightMode));
Don Gagne's avatar
Don Gagne committed
    emit guidedModeChanged(_firmwarePlugin->isGuidedMode(this));
}

void Vehicle::_announceArmedChanged(bool armed)
{
    _say(QString("%1 %2").arg(_vehicleIdSpeech()).arg(armed ? tr("armed") : tr("disarmed")));
Gus Grubba's avatar
Gus Grubba committed
    if(armed) {
        //-- Keep track of armed coordinates
        _armedPosition = _coordinate;
        emit armedPositionChanged();
    }
void Vehicle::_setFlying(bool flying)
Don Gagne's avatar
Don Gagne committed
{
    if (_flying != flying) {
Don Gagne's avatar
Don Gagne committed
        _flying = flying;
        emit flyingChanged(flying);
    }
}

void Vehicle::_setLanding(bool landing)
{
    if (armed() && _landing != landing) {
        _landing = landing;
        emit landingChanged(landing);
    }
}

bool Vehicle::guidedModeSupported() const
Don Gagne's avatar
Don Gagne committed
{
    return _firmwarePlugin->isCapable(this, FirmwarePlugin::GuidedModeCapability);
bool Vehicle::pauseVehicleSupported() const
Don Gagne's avatar
Don Gagne committed
{
    return _firmwarePlugin->isCapable(this, FirmwarePlugin::PauseVehicleCapability);
}

bool Vehicle::orbitModeSupported() const
{
    return _firmwarePlugin->isCapable(this, FirmwarePlugin::OrbitModeCapability);
Gus Grubba's avatar
Gus Grubba committed
bool Vehicle::roiModeSupported() const
{
    return _firmwarePlugin->isCapable(this, FirmwarePlugin::ROIModeCapability);
}

bool Vehicle::takeoffVehicleSupported() const
{
    return _firmwarePlugin->isCapable(this, FirmwarePlugin::TakeoffVehicleCapability);
}

Don Gagne's avatar
 
Don Gagne committed
QString Vehicle::gotoFlightMode() const
{
    return _firmwarePlugin->gotoFlightMode();
}

DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::guidedModeRTL(bool smartRTL)
Don Gagne's avatar
Don Gagne committed
{
    if (!guidedModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
Don Gagne's avatar
Don Gagne committed
        return;
    }
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _firmwarePlugin->guidedModeRTL(this, smartRTL);
void Vehicle::guidedModeLand()
Don Gagne's avatar
Don Gagne committed
{
    if (!guidedModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
Don Gagne's avatar
Don Gagne committed
        return;
    }
    _firmwarePlugin->guidedModeLand(this);
}

void Vehicle::guidedModeTakeoff(double altitudeRelative)
Don Gagne's avatar
Don Gagne committed
{
    if (!guidedModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
Don Gagne's avatar
Don Gagne committed
        return;
    }
    _firmwarePlugin->guidedModeTakeoff(this, altitudeRelative);
double Vehicle::minimumTakeoffAltitude()
{
    return _firmwarePlugin->minimumTakeoffAltitude(this);
}

void Vehicle::startMission()
{
    _firmwarePlugin->startMission(this);
Don Gagne's avatar
Don Gagne committed
}

void Vehicle::guidedModeGotoLocation(const QGeoCoordinate& gotoCoord)
{
    if (!guidedModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
Don Gagne's avatar
Don Gagne committed
        return;
    }
DonLakeFlyer's avatar
DonLakeFlyer committed
    if (!coordinate().isValid()) {
        return;
    }
Don Gagne's avatar
 
Don Gagne committed
    double maxDistance = _settingsManager->flyViewSettings()->maxGoToLocationDistance()->rawValue().toDouble();
DonLakeFlyer's avatar
DonLakeFlyer committed
    if (coordinate().distanceTo(gotoCoord) > maxDistance) {
Remek Zajac's avatar
Remek Zajac committed
        qgcApp()->showAppMessage(QString("New location is too far. Must be less than %1 %2.").arg(qRound(FactMetaData::metersToAppSettingsHorizontalDistanceUnits(maxDistance).toDouble())).arg(FactMetaData::appSettingsHorizontalDistanceUnitsString()));
DonLakeFlyer's avatar
DonLakeFlyer committed
        return;
    }
Don Gagne's avatar
Don Gagne committed
    _firmwarePlugin->guidedModeGotoLocation(this, gotoCoord);
}

void Vehicle::guidedModeChangeAltitude(double altitudeChange)
Don Gagne's avatar
Don Gagne committed
{
    if (!guidedModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
Don Gagne's avatar
Don Gagne committed
        return;
    }
    _firmwarePlugin->guidedModeChangeAltitude(this, altitudeChange);
DonLakeFlyer's avatar
DonLakeFlyer committed
void Vehicle::guidedModeOrbit(const QGeoCoordinate& centerCoord, double radius, double amslAltitude)
    if (!orbitModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(QStringLiteral("Orbit mode not supported by Vehicle."));
Don Gagne's avatar
 
Don Gagne committed
    if (capabilityBits() & MAV_PROTOCOL_CAPABILITY_COMMAND_INT) {
Gus Grubba's avatar
Gus Grubba committed
        sendMavCommandInt(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    defaultComponentId(),
                    MAV_CMD_DO_ORBIT,
                    MAV_FRAME_GLOBAL,
                    true,                           // show error if fails
                    static_cast<float>(radius),
                    static_cast<float>(qQNaN()),    // Use default velocity
                    0,                              // Vehicle points to center
                    static_cast<float>(qQNaN()),    // reserved
                    centerCoord.latitude(), centerCoord.longitude(), static_cast<float>(amslAltitude));
    } else {
Gus Grubba's avatar
Gus Grubba committed
        sendMavCommand(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    defaultComponentId(),
                    MAV_CMD_DO_ORBIT,
                    true,                           // show error if fails
                    static_cast<float>(radius),
                    static_cast<float>(qQNaN()),    // Use default velocity
                    0,                              // Vehicle points to center
                    static_cast<float>(qQNaN()),    // reserved
                    static_cast<float>(centerCoord.latitude()),
                    static_cast<float>(centerCoord.longitude()),
                    static_cast<float>(amslAltitude));
Gus Grubba's avatar
Gus Grubba committed
void Vehicle::guidedModeROI(const QGeoCoordinate& centerCoord)
{
    if (!roiModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(QStringLiteral("ROI mode not supported by Vehicle."));
Gus Grubba's avatar
Gus Grubba committed
        return;
    }
    if (capabilityBits() & MAV_PROTOCOL_CAPABILITY_COMMAND_INT) {
        sendMavCommandInt(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    defaultComponentId(),
                    MAV_CMD_DO_SET_ROI_LOCATION,
                    MAV_FRAME_GLOBAL,
                    true,                           // show error if fails
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    centerCoord.latitude(),
                    centerCoord.longitude(),
                    static_cast<float>(centerCoord.altitude()));
Gus Grubba's avatar
Gus Grubba committed
    } else {
        sendMavCommand(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    defaultComponentId(),
                    MAV_CMD_DO_SET_ROI_LOCATION,
                    true,                           // show error if fails
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(centerCoord.latitude()),
                    static_cast<float>(centerCoord.longitude()),
                    static_cast<float>(centerCoord.altitude()));
void Vehicle::stopGuidedModeROI()
{
    if (!roiModeSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(QStringLiteral("ROI mode not supported by Vehicle."));
        return;
    }
    if (capabilityBits() & MAV_PROTOCOL_CAPABILITY_COMMAND_INT) {
        sendMavCommandInt(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    defaultComponentId(),
                    MAV_CMD_DO_SET_ROI_NONE,
                    MAV_FRAME_GLOBAL,
                    true,                           // show error if fails
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<double>(qQNaN()),   // Empty
                    static_cast<double>(qQNaN()),   // Empty
                    static_cast<float>(qQNaN()));   // Empty
    } else {
        sendMavCommand(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                    defaultComponentId(),
                    MAV_CMD_DO_SET_ROI_NONE,
                    true,                           // show error if fails
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()),    // Empty
                    static_cast<float>(qQNaN()));   // Empty
void Vehicle::pauseVehicle()
Don Gagne's avatar
Don Gagne committed
{
    if (!pauseVehicleSupported()) {
DoinLakeFlyer's avatar
 
DoinLakeFlyer committed
        qgcApp()->showAppMessage(QStringLiteral("Pause not supported by vehicle."));
Don Gagne's avatar
Don Gagne committed
        return;
    }
    _firmwarePlugin->pauseVehicle(this);
}

void Vehicle::abortLanding(double climbOutAltitude)
Gus Grubba's avatar
Gus Grubba committed
    sendMavCommand(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                defaultComponentId(),
                MAV_CMD_DO_GO_AROUND,
                true,        // show error if fails
                static_cast<float>(climbOutAltitude));
bool Vehicle::guidedMode() const
Don Gagne's avatar
Don Gagne committed
{
    return _firmwarePlugin->isGuidedMode(this);
}

void Vehicle::setGuidedMode(bool guidedMode)
{
    return _firmwarePlugin->setGuidedMode(this, guidedMode);
}

void Vehicle::emergencyStop()
Don Gagne's avatar
Don Gagne committed
{
Gus Grubba's avatar
Gus Grubba committed
    sendMavCommand(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                _defaultComponentId,
                MAV_CMD_COMPONENT_ARM_DISARM,
                true,        // show error if fails
                0.0f,
                21196.0f);  // Magic number for emergency stop
void Vehicle::setCurrentMissionSequence(int seq)
{
    if (!_firmwarePlugin->sendHomePositionToVehicle()) {
        seq--;
    }
    mavlink_message_t msg;
Gus Grubba's avatar
Gus Grubba committed
    mavlink_msg_mission_set_current_pack_chan(
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                static_cast<uint8_t>(_mavlink->getSystemId()),
                static_cast<uint8_t>(_mavlink->getComponentId()),
                priorityLink()->mavlinkChannel(),
                &msg,
                static_cast<uint8_t>(id()),
                _compID,
                static_cast<uint16_t>(seq));
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    sendMessageOnLinkThreadSafe(priorityLink(), msg);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::sendMavCommand(int compId, MAV_CMD command, bool showError, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
Don Gagne's avatar
Don Gagne committed
{
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _sendMavCommandWorker(false,            // commandInt
                          false,            // requestMessage
                          showError,
                          nullptr,          // resultHandler
                          nullptr,          // resultHandlerData
                          compId,
                          command,
                          MAV_FRAME_GLOBAL,
                          param1, param2, param3, param4, param5, param6, param7);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
}

DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::sendMavCommandWithHandler(MavCmdResultHandler resultHandler, void *resultHandlerData, int compId, MAV_CMD command, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
DonLakeFlyer's avatar
 
DonLakeFlyer committed
{
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _sendMavCommandWorker(false,                // commandInt
                          false,                // requestMessage,
                          false,                // showError
                          resultHandler,
                          resultHandlerData,
                          compId,
                          command,
                          MAV_FRAME_GLOBAL,
                          param1, param2, param3, param4, param5, param6, param7);
}
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::sendMavCommandInt(int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
{
    _sendMavCommandWorker(true,         // commandInt
                          false,        // requestMessage
                          showError,
                          nullptr,      // resultHandler
                          nullptr,      // resultHandlerData
                          compId,
                          command,
                          frame,
                          param1, param2, param3, param4, param5, param6, param7);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::_sendMavCommandWorker(bool commandInt, bool requestMessage, bool showError, MavCmdResultHandler resultHandler, void* resultHandlerData, int compId, MAV_CMD command, MAV_FRAME frame, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
{
    MavCommandQueueEntry_t entry;

DonLakeFlyer's avatar
 
DonLakeFlyer committed
    entry.commandInt        = commandInt;
    entry.compId            = compId;
    entry.command           = command;
    entry.frame             = frame;
    entry.showError         = showError;
    entry.requestMessage    = requestMessage;
    entry.resultHandler     = resultHandler;
    entry.resultHandlerData = resultHandlerData;
    entry.rgParam[0]        = param1;
    entry.rgParam[1]        = param2;
    entry.rgParam[2]        = param3;
    entry.rgParam[3]        = param4;
    entry.rgParam[4]        = param5;
    entry.rgParam[5]        = param6;
    entry.rgParam[6]        = param7;

    _mavCommandQueue.enqueue(entry);

    if (_mavCommandQueue.count() == 1) {
        _mavCommandRetryCount = 0;
        _sendMavCommandAgain();
    }
}

void Vehicle::_sendMavCommandAgain()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    if(_mavCommandQueue.isEmpty()) {
        qWarning() << "Command resend with no commands in queue";
        _mavCommandAckTimer.stop();