Skip to content
Snippets Groups Projects
Vehicle.cc 182 KiB
Newer Older
  • Learn to ignore specific revisions
  •     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
    
    {
        return _firmwarePlugin->supportsMotorInterference();
    }
    
    
    bool Vehicle::supportsTerrainFrame() const
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        return _capabilityBits & MAV_PROTOCOL_CAPABILITY_TERRAIN;
    
    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")));
    
        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(
                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));
    
    Gus Grubba's avatar
    Gus Grubba committed
            sendMavCommand(
                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(
                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
    
    Gus Grubba's avatar
    Gus Grubba committed
                centerCoord.latitude(),
                centerCoord.longitude(),
                static_cast<float>(centerCoord.altitude()));
    
    Gus Grubba's avatar
    Gus Grubba committed
        } else {
            sendMavCommand(
                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(
                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(
                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(
            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(
            _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(
            static_cast<uint8_t>(_mavlink->getSystemId()),
            static_cast<uint8_t>(_mavlink->getComponentId()),
            priorityLink()->mavlinkChannel(),
            &msg,
            static_cast<uint8_t>(id()),
            _compID,
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
            static_cast<uint16_t>(seq));
    
        sendMessageOnLink(priorityLink(), msg);
    
    void Vehicle::sendMavCommand(int component, MAV_CMD command, bool showError, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
    
        MavCommandQueueEntry_t entry;
    
    
        entry.commandInt = false;
    
        entry.component = component;
        entry.command = command;
        entry.showError = showError;
    
    Gus Grubba's avatar
    Gus Grubba committed
        entry.rgParam[0] = static_cast<double>(param1);
        entry.rgParam[1] = static_cast<double>(param2);
        entry.rgParam[2] = static_cast<double>(param3);
        entry.rgParam[3] = static_cast<double>(param4);
        entry.rgParam[4] = static_cast<double>(param5);
        entry.rgParam[5] = static_cast<double>(param6);
        entry.rgParam[6] = static_cast<double>(param7);
    
    
        _mavCommandQueue.append(entry);
    
        if (_mavCommandQueue.count() == 1) {
            _mavCommandRetryCount = 0;
            _sendMavCommandAgain();
        }
    }
    
    
    void Vehicle::sendMavCommandInt(int component, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
    {
        MavCommandQueueEntry_t entry;
    
        entry.commandInt = true;
    
        entry.component = component;
        entry.command = command;
    
        entry.frame = frame;
    
        entry.showError = showError;
    
    Gus Grubba's avatar
    Gus Grubba committed
        entry.rgParam[0] = static_cast<double>(param1);
        entry.rgParam[1] = static_cast<double>(param2);
        entry.rgParam[2] = static_cast<double>(param3);
        entry.rgParam[3] = static_cast<double>(param4);
    
        entry.rgParam[4] = param5;
        entry.rgParam[5] = param6;
    
    Gus Grubba's avatar
    Gus Grubba committed
        entry.rgParam[6] = static_cast<double>(param7);
    
    
        _mavCommandQueue.append(entry);
    
        if (_mavCommandQueue.count() == 1) {
            _mavCommandRetryCount = 0;
            _sendMavCommandAgain();
        }
    }
    
    
    void Vehicle::_sendMavCommandAgain()
    
        if(!_mavCommandQueue.size()) {
            qWarning() << "Command resend with no commands in queue";
            _mavCommandAckTimer.stop();
            return;
        }
    
    
        MavCommandQueueEntry_t& queuedCommand = _mavCommandQueue[0];
    
        if (_mavCommandRetryCount++ > _mavCommandMaxRetryCount) {
    
            if (queuedCommand.command == MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES) {
    
    Don Gagne's avatar
     
    Don Gagne committed
                qCDebug(VehicleLog) << "Vehicle failed to responded to MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES.";
                _handleUnsupportedRequestAutopilotCapabilities();
    
            if (queuedCommand.command == MAV_CMD_REQUEST_PROTOCOL_VERSION) {
    
    Don Gagne's avatar
     
    Don Gagne committed
                qCDebug(VehicleLog) << "Vehicle failed to responded to MAV_CMD_REQUEST_PROTOCOL_VERSION.";
                _handleUnsupportedRequestProtocolVersion();
    
            emit mavCommandResult(_id, queuedCommand.component, queuedCommand.command, MAV_RESULT_FAILED, true /* noResponsefromVehicle */);
            if (queuedCommand.showError) {
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
                qgcApp()->showAppMessage(tr("Vehicle did not respond to command: %1").arg(_toolbox->missionCommandTree()->friendlyName(queuedCommand.command)));
    
            }
            _mavCommandQueue.removeFirst();
            _sendNextQueuedMavCommand();
            return;
        }
    
    
        if (_mavCommandRetryCount > 1) {
    
    Don Gagne's avatar
     
    Don Gagne committed
            if (!px4Firmware() && queuedCommand.command == MAV_CMD_START_RX_PAIR) {
                // The implementation of this command comes from the IO layer and is shared across stacks. So for other firmwares
                // we aren't really sure whether they are correct or not.
                return;
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            qCDebug(VehicleLog) << "Vehicle::_sendMavCommandAgain retrying command:_mavCommandRetryCount" << queuedCommand.command << _mavCommandRetryCount;
    
        _mavCommandAckTimer.start();
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        qCDebug(VehicleLog) << "_sendMavCommandAgain sending" << queuedCommand.command;
    
    
    Don Gagne's avatar
    Don Gagne committed
        mavlink_message_t       msg;
    
        if (queuedCommand.commandInt) {
            mavlink_command_int_t  cmd;
    
            memset(&cmd, 0, sizeof(cmd));
            cmd.target_system =     _id;
            cmd.target_component =  queuedCommand.component;
            cmd.command =           queuedCommand.command;
            cmd.frame =             queuedCommand.frame;
            cmd.param1 =            queuedCommand.rgParam[0];
            cmd.param2 =            queuedCommand.rgParam[1];
            cmd.param3 =            queuedCommand.rgParam[2];
            cmd.param4 =            queuedCommand.rgParam[3];
            cmd.x =                 queuedCommand.rgParam[4] * qPow(10.0, 7.0);
            cmd.y =                 queuedCommand.rgParam[5] * qPow(10.0, 7.0);
            cmd.z =                 queuedCommand.rgParam[6];
            mavlink_msg_command_int_encode_chan(_mavlink->getSystemId(),
                                                _mavlink->getComponentId(),
                                                priorityLink()->mavlinkChannel(),
                                                &msg,
                                                &cmd);
        } else {
            mavlink_command_long_t  cmd;
    
            memset(&cmd, 0, sizeof(cmd));
            cmd.target_system =     _id;
            cmd.target_component =  queuedCommand.component;
            cmd.command =           queuedCommand.command;
            cmd.confirmation =      0;
            cmd.param1 =            queuedCommand.rgParam[0];
            cmd.param2 =            queuedCommand.rgParam[1];
            cmd.param3 =            queuedCommand.rgParam[2];
            cmd.param4 =            queuedCommand.rgParam[3];
            cmd.param5 =            queuedCommand.rgParam[4];
            cmd.param6 =            queuedCommand.rgParam[5];
            cmd.param7 =            queuedCommand.rgParam[6];
            mavlink_msg_command_long_encode_chan(_mavlink->getSystemId(),
                                                 _mavlink->getComponentId(),
                                                 priorityLink()->mavlinkChannel(),
                                                 &msg,
                                                 &cmd);
        }
    
        sendMessageOnLink(priorityLink(), msg);
    
    void Vehicle::_sendNextQueuedMavCommand()
    
    {
        if (_mavCommandQueue.count()) {
            _mavCommandRetryCount = 0;
            _sendMavCommandAgain();
        }
    }
    
    
    void Vehicle::_handleUnsupportedRequestProtocolVersion()
    
    Don Gagne's avatar
     
    Don Gagne committed
    {
        // We end up here if either the vehicle does not support the MAV_CMD_REQUEST_PROTOCOL_VERSION command or if
        // we never received an Ack back for the command.
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        // _mavlinkProtocolRequestMaxProtoVersion stays at 0 to indicate unknown
    
    Don Gagne's avatar
     
    Don Gagne committed
        _mavlinkProtocolRequestComplete = true;
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        _setMaxProtoVersionFromBothSources();
    
    Don Gagne's avatar
     
    Don Gagne committed
    
        // Determining protocol version is one of the triggers to possibly start downloading the plan
        _startPlanRequest();
    }
    
    
    void Vehicle::_protocolVersionTimeOut()
    
    Don Gagne's avatar
     
    Don Gagne committed
    {
        // The PROTOCOL_VERSION message didn't make it through the pipe from Vehicle->QGC.
    
    Don Gagne's avatar
     
    Don Gagne committed
        // This means although the vehicle may support mavlink 2, the pipe does not.
    
    Don Gagne's avatar
     
    Don Gagne committed
        qCDebug(VehicleLog) << QStringLiteral("Setting _maxProtoVersion to 100 due to timeout on receiving PROTOCOL_VERSION message.");
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        _mavlinkProtocolRequestMaxProtoVersion = 100;
    
    Don Gagne's avatar
     
    Don Gagne committed
        _mavlinkProtocolRequestComplete = true;
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        _setMaxProtoVersionFromBothSources();
    
    Don Gagne's avatar
     
    Don Gagne committed
        _startPlanRequest();
    }
    
    
    void Vehicle::_handleUnsupportedRequestAutopilotCapabilities()
    
    Don Gagne's avatar
     
    Don Gagne committed
    {
        // We end up here if either the vehicle does not support the MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES command or if
        // we never received an Ack back for the command.
    
        _setCapabilities(0);
    
        // Determining vehicle capabilities is one of the triggers to possibly start downloading the plan
        _startPlanRequest();
    }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
    void Vehicle::_handleCommandAck(mavlink_message_t& message)
    {
        bool showError = false;
    
        mavlink_command_ack_t ack;
        mavlink_msg_command_ack_decode(&message, &ack);
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        qCDebug(VehicleLog) << QStringLiteral("_handleCommandAck command(%1) result(%2)").arg(ack.command).arg(ack.result);
    
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        if (ack.command == MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES && ack.result != MAV_RESULT_ACCEPTED) {
    
    Don Gagne's avatar
     
    Don Gagne committed
            qCDebug(VehicleLog) << QStringLiteral("Vehicle responded to MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES with error(%1). Setting no capabilities.").arg(ack.result);
            _handleUnsupportedRequestAutopilotCapabilities();
    
    Don Gagne's avatar
     
    Don Gagne committed
        if (ack.command == MAV_CMD_REQUEST_PROTOCOL_VERSION) {
            if (ack.result == MAV_RESULT_ACCEPTED) {
                // The vehicle should be sending a PROTOCOL_VERSION message in a mavlink 2 packet. This may or may not make it through the pipe.
                // So we wait for it to come and timeout if it doesn't.
                if (!_mavlinkProtocolRequestComplete) {
                    QTimer::singleShot(1000, this, &Vehicle::_protocolVersionTimeOut);
                }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            } else {
    
    Don Gagne's avatar
     
    Don Gagne committed
                qCDebug(VehicleLog) << QStringLiteral("Vehicle responded to MAV_CMD_REQUEST_PROTOCOL_VERSION with error(%1).").arg(ack.result);
                _handleUnsupportedRequestProtocolVersion();
    
        if (ack.command == MAV_CMD_DO_SET_ROI_LOCATION) {
            if (ack.result == MAV_RESULT_ACCEPTED) {
                _isROIEnabled = true;
                emit isROIEnabledChanged();
            }
        }
    
        if (ack.command == MAV_CMD_DO_SET_ROI_NONE) {
            if (ack.result == MAV_RESULT_ACCEPTED) {
                _isROIEnabled = false;
                emit isROIEnabledChanged();
            }
        }
    
    
    #if !defined(NO_ARDUPILOT_DIALECT)
    
    Don Gagne's avatar
     
    Don Gagne committed
        if (ack.command == MAV_CMD_FLASH_BOOTLOADER && ack.result == MAV_RESULT_ACCEPTED) {
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
            qgcApp()->showAppMessage(tr("Bootloader flash succeeded"));
    
    Don Gagne's avatar
     
    Don Gagne committed
        }
    
    #endif
    
    Don Gagne's avatar
     
    Don Gagne committed
    
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        if (_mavCommandQueue.count() && ack.command == _mavCommandQueue[0].command) {
            _mavCommandAckTimer.stop();
            showError = _mavCommandQueue[0].showError;
            _mavCommandQueue.removeFirst();
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
            _sendNextQueuedMavCommand();
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        }
    
        emit mavCommandResult(_id, message.compid, ack.command, ack.result, false /* noResponsefromVehicle */);
    
        if (showError) {
    
    Gus Grubba's avatar
    Gus Grubba committed
            QString commandName = _toolbox->missionCommandTree()->friendlyName(static_cast<MAV_CMD>(ack.command));
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            switch (ack.result) {
            case MAV_RESULT_TEMPORARILY_REJECTED:
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
                qgcApp()->showAppMessage(tr("%1 command temporarily rejected").arg(commandName));
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                break;
            case MAV_RESULT_DENIED:
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
                qgcApp()->showAppMessage(tr("%1 command denied").arg(commandName));
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                break;
            case MAV_RESULT_UNSUPPORTED:
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
                qgcApp()->showAppMessage(tr("%1 command not supported").arg(commandName));
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                break;
            case MAV_RESULT_FAILED:
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
                qgcApp()->showAppMessage(tr("%1 command failed").arg(commandName));
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                break;
            default:
                // Do nothing
                break;
            }
        }
    }
    
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::setPrearmError(const QString& prearmError)
    {
        _prearmError = prearmError;
        emit prearmErrorChanged(_prearmError);
        if (!_prearmError.isEmpty()) {
            _prearmErrorTimer.start();
        }
    }
    
    
    void Vehicle::_prearmErrorTimeout()
    
    Don Gagne's avatar
    Don Gagne committed
    {
        setPrearmError(QString());
    }
    
    void Vehicle::setFirmwareVersion(int majorVersion, int minorVersion, int patchVersion, FIRMWARE_VERSION_TYPE versionType)
    
    Don Gagne's avatar
    Don Gagne committed
    {
        _firmwareMajorVersion = majorVersion;
        _firmwareMinorVersion = minorVersion;
        _firmwarePatchVersion = patchVersion;
    
        _firmwareVersionType = versionType;
    
        emit firmwareVersionChanged();
    }
    
    void Vehicle::setFirmwareCustomVersion(int majorVersion, int minorVersion, int patchVersion)
    {
        _firmwareCustomMajorVersion = majorVersion;
        _firmwareCustomMinorVersion = minorVersion;
        _firmwareCustomPatchVersion = patchVersion;
        emit firmwareCustomVersionChanged();
    
    QString Vehicle::firmwareVersionTypeString() const
    
    {
        switch (_firmwareVersionType) {
        case FIRMWARE_VERSION_TYPE_DEV:
            return QStringLiteral("dev");
        case FIRMWARE_VERSION_TYPE_ALPHA:
            return QStringLiteral("alpha");
        case FIRMWARE_VERSION_TYPE_BETA:
            return QStringLiteral("beta");
        case FIRMWARE_VERSION_TYPE_RC:
            return QStringLiteral("rc");
        case FIRMWARE_VERSION_TYPE_OFFICIAL:
        default:
            return QStringLiteral("");
        }
    
    void Vehicle::rebootVehicle()
    {
    
        _autoDisconnect = true;
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    
        mavlink_message_t       msg;
        mavlink_command_long_t  cmd;
    
        memset(&cmd, 0, sizeof(cmd));
        cmd.target_system =     _id;
        cmd.target_component =  _defaultComponentId;
        cmd.command =           MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN;
        cmd.confirmation =      0;
        cmd.param1 =            1;
        cmd.param2 = cmd.param3 = cmd.param4 = cmd.param5 = cmd.param6 = cmd.param7 = 0;
        mavlink_msg_command_long_encode_chan(_mavlink->getSystemId(),
                                             _mavlink->getComponentId(),
                                             priorityLink()->mavlinkChannel(),
                                             &msg,
                                             &cmd);
        sendMessageOnLink(priorityLink(), msg);
    
    void Vehicle::setSoloFirmware(bool soloFirmware)
    {
        if (soloFirmware != _soloFirmware) {
            _soloFirmware = soloFirmware;
            emit soloFirmwareChanged(soloFirmware);
        }
    }
    
    
    Don Gagne's avatar
     
    Don Gagne committed
    void Vehicle::motorTest(int motor, int percent, int timeoutSecs)
    
    Don Gagne's avatar
     
    Don Gagne committed
        sendMavCommand(_defaultComponentId, MAV_CMD_DO_MOTOR_TEST, true, motor, MOTOR_TEST_THROTTLE_PERCENT, percent, timeoutSecs, 0, MOTOR_TEST_ORDER_BOARD);
    
    QString Vehicle::brandImageIndoor() const
    
        return _firmwarePlugin->brandImageIndoor(this);
    }
    
    
    QString Vehicle::brandImageOutdoor() const
    
    {
        return _firmwarePlugin->brandImageOutdoor(this);
    
    QStringList Vehicle::unhealthySensors() const
    
    {
        QStringList sensorList;
    
        struct sensorInfo_s {
            uint32_t    bit;
            const char* sensorName;
        };
    
        static const sensorInfo_s rgSensorInfo[] = {
            { MAV_SYS_STATUS_SENSOR_3D_GYRO,                "Gyro" },
            { MAV_SYS_STATUS_SENSOR_3D_ACCEL,               "Accelerometer" },
            { MAV_SYS_STATUS_SENSOR_3D_MAG,                 "Magnetometer" },
            { MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE,      "Absolute pressure" },
            { MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE,  "Differential pressure" },
            { MAV_SYS_STATUS_SENSOR_GPS,                    "GPS" },
            { MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW,           "Optical flow" },
            { MAV_SYS_STATUS_SENSOR_VISION_POSITION,        "Computer vision position" },
            { MAV_SYS_STATUS_SENSOR_LASER_POSITION,         "Laser based position" },
            { MAV_SYS_STATUS_SENSOR_EXTERNAL_GROUND_TRUTH,  "External ground truth" },
            { MAV_SYS_STATUS_SENSOR_ANGULAR_RATE_CONTROL,   "Angular rate control" },
            { MAV_SYS_STATUS_SENSOR_ATTITUDE_STABILIZATION, "Attitude stabilization" },
            { MAV_SYS_STATUS_SENSOR_YAW_POSITION,           "Yaw position" },
            { MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL,     "Z/altitude control" },
            { MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL,    "X/Y position control" },
            { MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS,          "Motor outputs / control" },
            { MAV_SYS_STATUS_SENSOR_RC_RECEIVER,            "RC receiver" },
            { MAV_SYS_STATUS_SENSOR_3D_GYRO2,               "Gyro 2" },
            { MAV_SYS_STATUS_SENSOR_3D_ACCEL2,              "Accelerometer 2" },
            { MAV_SYS_STATUS_SENSOR_3D_MAG2,                "Magnetometer 2" },
            { MAV_SYS_STATUS_GEOFENCE,                      "GeoFence" },
            { MAV_SYS_STATUS_AHRS,                          "AHRS" },
            { MAV_SYS_STATUS_TERRAIN,                       "Terrain" },
            { MAV_SYS_STATUS_REVERSE_MOTOR,                 "Motors reversed" },
            { MAV_SYS_STATUS_LOGGING,                       "Logging" },
    
            { MAV_SYS_STATUS_SENSOR_BATTERY,                "Battery" },
    
        };
    
        for (size_t i=0; i<sizeof(rgSensorInfo)/sizeof(sensorInfo_s); i++) {
            const sensorInfo_s* pSensorInfo = &rgSensorInfo[i];
            if ((_onboardControlSensorsEnabled & pSensorInfo->bit) && !(_onboardControlSensorsHealth & pSensorInfo->bit)) {
                sensorList << pSensorInfo->sensorName;
            }
        }
    
        return sensorList;
    }
    
    
    void Vehicle::setOfflineEditingDefaultComponentId(int defaultComponentId)
    {
        if (_offlineEditingVehicle) {
            _defaultComponentId = defaultComponentId;
        } else {
            qWarning() << "Call to Vehicle::setOfflineEditingDefaultComponentId on vehicle which is not offline";
        }
    }
    
    void Vehicle::triggerCamera()
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        sendMavCommand(_defaultComponentId,
    
    Don Gagne's avatar
    Don Gagne committed
                       MAV_CMD_DO_DIGICAM_CONTROL,
                       true,                            // show errors
                       0.0, 0.0, 0.0, 0.0,              // param 1-4 unused
    
                       1.0,                             // trigger camera
                       0.0,                             // param 6 unused
                       1.0);                            // test shot flag
    
    void Vehicle::setVtolInFwdFlight(bool vtolInFwdFlight)
    {
        if (_vtolInFwdFlight != vtolInFwdFlight) {
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            sendMavCommand(_defaultComponentId,
                           MAV_CMD_DO_VTOL_TRANSITION,
                           true,                                                    // show errors
                           vtolInFwdFlight ? MAV_VTOL_STATE_FW : MAV_VTOL_STATE_MC, // transition state
                           0, 0, 0, 0, 0, 0);                                       // param 2-7 unused
    
    const char* VehicleGPSFactGroup::_latFactName =                 "lat";
    const char* VehicleGPSFactGroup::_lonFactName =                 "lon";
    
    const char* VehicleGPSFactGroup::_mgrsFactName =                "mgrs";
    
    const char* VehicleGPSFactGroup::_hdopFactName =                "hdop";
    const char* VehicleGPSFactGroup::_vdopFactName =                "vdop";
    const char* VehicleGPSFactGroup::_courseOverGroundFactName =    "courseOverGround";
    const char* VehicleGPSFactGroup::_countFactName =               "count";
    const char* VehicleGPSFactGroup::_lockFactName =                "lock";
    
    Don Gagne's avatar
    Don Gagne committed
    
    VehicleGPSFactGroup::VehicleGPSFactGroup(QObject* parent)
        : FactGroup(1000, ":/json/Vehicle/GPSFact.json", parent)
    
        , _latFact              (0, _latFactName,               FactMetaData::valueTypeDouble)
        , _lonFact              (0, _lonFactName,               FactMetaData::valueTypeDouble)
    
        , _mgrsFact             (0, _mgrsFactName,              FactMetaData::valueTypeString)
    
    Don Gagne's avatar
    Don Gagne committed
        , _hdopFact             (0, _hdopFactName,              FactMetaData::valueTypeDouble)
        , _vdopFact             (0, _vdopFactName,              FactMetaData::valueTypeDouble)
        , _courseOverGroundFact (0, _courseOverGroundFactName,  FactMetaData::valueTypeDouble)
        , _countFact            (0, _countFactName,             FactMetaData::valueTypeInt32)
        , _lockFact             (0, _lockFactName,              FactMetaData::valueTypeInt32)
    {
    
        _addFact(&_latFact,                 _latFactName);
        _addFact(&_lonFact,                 _lonFactName);
    
        _addFact(&_mgrsFact,                _mgrsFactName);
    
    Don Gagne's avatar
    Don Gagne committed
        _addFact(&_hdopFact,                _hdopFactName);
        _addFact(&_vdopFact,                _vdopFactName);
        _addFact(&_courseOverGroundFact,    _courseOverGroundFactName);
        _addFact(&_lockFact,                _lockFactName);
        _addFact(&_countFact,               _countFactName);
    
        _latFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _lonFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
        _mgrsFact.setRawValue("");
    
        _hdopFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _vdopFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _courseOverGroundFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
    void Vehicle::startMavlinkLog()
    
        sendMavCommand(_defaultComponentId, MAV_CMD_LOGGING_START, false /* showError */);
    
    void Vehicle::stopMavlinkLog()
    
        sendMavCommand(_defaultComponentId, MAV_CMD_LOGGING_STOP, false /* showError */);
    
    void Vehicle::_ackMavlinkLogData(uint16_t sequence)
    
    {
        mavlink_message_t msg;
        mavlink_logging_ack_t ack;
    
    Don Gagne's avatar
    Don Gagne committed
        memset(&ack, 0, sizeof(ack));
    
        ack.target_component = _defaultComponentId;
    
        ack.target_system = id();
        mavlink_msg_logging_ack_encode_chan(
    
                    _mavlink->getSystemId(),
                    _mavlink->getComponentId(),
                    priorityLink()->mavlinkChannel(),
                    &msg,
                    &ack);
    
        sendMessageOnLink(priorityLink(), msg);
    }
    
    
    void Vehicle::_handleMavlinkLoggingData(mavlink_message_t& message)
    
    {
        mavlink_logging_data_t log;
        mavlink_msg_logging_data_decode(&message, &log);
    
    Gus Grubba's avatar
    Gus Grubba committed
        emit mavlinkLogData(this, log.target_system, log.target_component, log.sequence,
    
                            log.first_message_offset, QByteArray((const char*)log.data, log.length), false);
    
    void Vehicle::_handleMavlinkLoggingDataAcked(mavlink_message_t& message)
    
        mavlink_logging_data_acked_t log;
        mavlink_msg_logging_data_acked_decode(&message, &log);
    
        _ackMavlinkLogData(log.sequence);
    
    Gus Grubba's avatar
    Gus Grubba committed
        emit mavlinkLogData(this, log.target_system, log.target_component, log.sequence,
    
                            log.first_message_offset, QByteArray((const char*)log.data, log.length), true);
    
    void Vehicle::setFirmwarePluginInstanceData(QObject* firmwarePluginInstanceData)
    {
        firmwarePluginInstanceData->setParent(this);
        _firmwarePluginInstanceData = firmwarePluginInstanceData;
    }
    
    
    QString Vehicle::missionFlightMode() const
    
    {
        return _firmwarePlugin->missionFlightMode();
    }
    
    
    QString Vehicle::pauseFlightMode() const
    
    {
        return _firmwarePlugin->pauseFlightMode();
    }
    
    
    QString Vehicle::rtlFlightMode() const
    
    {
        return _firmwarePlugin->rtlFlightMode();
    }
    
    
    QString Vehicle::smartRTLFlightMode() const
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    {
        return _firmwarePlugin->smartRTLFlightMode();
    }
    
    
    bool Vehicle::supportsSmartRTL() const
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    {
        return _firmwarePlugin->supportsSmartRTL();
    }
    
    
    QString Vehicle::landFlightMode() const
    
    {
        return _firmwarePlugin->landFlightMode();
    }
    
    
    QString Vehicle::takeControlFlightMode() const
    
    {
        return _firmwarePlugin->takeControlFlightMode();
    }
    
    
    QString Vehicle::followFlightMode() const
    
    Don Gagne's avatar
     
    Don Gagne committed
    {
        return _firmwarePlugin->followFlightMode();
    }
    
    
    QString Vehicle::vehicleImageOpaque() const
    {
        if(_firmwarePlugin)
            return _firmwarePlugin->vehicleImageOpaque(this);
        else
            return QString();
    }
    
    QString Vehicle::vehicleImageOutline() const
    {
        if(_firmwarePlugin)
            return _firmwarePlugin->vehicleImageOutline(this);
        else
            return QString();
    }
    
    QString Vehicle::vehicleImageCompass() const
    {
        if(_firmwarePlugin)
            return _firmwarePlugin->vehicleImageCompass(this);
        else
            return QString();
    }
    
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
    const QVariantList& Vehicle::toolIndicators()
    {
        if(_firmwarePlugin) {
            return _firmwarePlugin->toolIndicators(this);
        }
        static QVariantList emptyList;
        return emptyList;
    }
    
    const QVariantList& Vehicle::modeIndicators()
    
    DoinLakeFlyer's avatar
     
    DoinLakeFlyer committed
            return _firmwarePlugin->modeIndicators(this);
    
        }
        static QVariantList emptyList;
        return emptyList;
    }
    
    
    const QVariantList& Vehicle::staticCameraList() const
    
    {
        if (_firmwarePlugin) {
            return _firmwarePlugin->cameraList(this);
        }
        static QVariantList emptyList;
        return emptyList;
    }
    
    
    bool Vehicle::vehicleYawsToNextWaypointInMission() const
    
    {
        return _firmwarePlugin->vehicleYawsToNextWaypointInMission(this);
    }
    
    void Vehicle::_setupAutoDisarmSignalling()
    
    {
        QString param = _firmwarePlugin->autoDisarmParameter(this);
    
        if (!param.isEmpty() && _parameterManager->parameterExists(FactSystem::defaultComponentId, param)) {
            Fact* fact = _parameterManager->getParameter(FactSystem::defaultComponentId,param);
            connect(fact, &Fact::rawValueChanged, this, &Vehicle::autoDisarmChanged);
            emit autoDisarmChanged();
        }
    }
    
    
    bool Vehicle::autoDisarm()
    
    {
        QString param = _firmwarePlugin->autoDisarmParameter(this);
    
        if (!param.isEmpty() && _parameterManager->parameterExists(FactSystem::defaultComponentId, param)) {
            Fact* fact = _parameterManager->getParameter(FactSystem::defaultComponentId,param);
            return fact->rawValue().toDouble() > 0;
        }
    
        return false;
    }
    
    
    void Vehicle::_handleADSBVehicle(const mavlink_message_t& message)
    {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        mavlink_adsb_vehicle_t adsbVehicleMsg;
    
    Don Gagne's avatar
    Don Gagne committed
        static const int maxTimeSinceLastSeen = 15;
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        mavlink_msg_adsb_vehicle_decode(&message, &adsbVehicleMsg);
        if (adsbVehicleMsg.flags | ADSB_FLAGS_VALID_COORDS && adsbVehicleMsg.tslc <= maxTimeSinceLastSeen) {
            ADSBVehicle::VehicleInfo_t vehicleInfo;
    
            vehicleInfo.availableFlags = 0;