Skip to content
Vehicle.cc 136 KiB
Newer Older
    _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()
    disconnect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &Vehicle::_firstGeoFenceLoadComplete);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _initialConnectStateMachine->advance();
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::_firstRallyPointLoadComplete()
    disconnect(_rallyPointManager, &RallyPointManager::loadComplete, this, &Vehicle::_firstRallyPointLoadComplete);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    _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(),
                                        vehicleLinkManager()->primaryLink()->mavlinkChannel(),
    sendMessageOnLinkThreadSafe(vehicleLinkManager()->primaryLink(), msg);
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::_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()),
                vehicleLinkManager()->primaryLink()->mavlinkChannel(),
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                &msg,
                static_cast<uint8_t>(id()),
                _compID,
                static_cast<uint16_t>(seq));
    sendMessageOnLinkThreadSafe(vehicleLinkManager()->primaryLink(), 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();
        return;
    }

DonLakeFlyer's avatar
 
DonLakeFlyer committed
    MavCommandQueueEntry_t& queuedCommand   = _mavCommandQueue[0];
    QString                 rawCommandName  =_toolbox->missionCommandTree()->rawName(queuedCommand.command);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    if (_mavCommandRetryCount++ >= _mavCommandMaxRetryCount) {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        if (queuedCommand.resultHandler) {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
            (*queuedCommand.resultHandler)(queuedCommand.resultHandlerData, queuedCommand.compId, MAV_RESULT_FAILED, true /* noResponsefromVehicle */);
        } else {
            emit mavCommandResult(_id, queuedCommand.compId, queuedCommand.command, MAV_RESULT_FAILED, true /* noResponsefromVehicle */);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        }
        if (queuedCommand.showError) {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
            qgcApp()->showAppMessage(tr("Vehicle did not respond to command: %1").arg(rawCommandName));
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        _mavCommandQueue.dequeue();
        _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" << rawCommandName << _mavCommandRetryCount;
    _mavCommandAckTimer.start();

DonLakeFlyer's avatar
 
DonLakeFlyer committed
    if (queuedCommand.requestMessage) {
        RequestMessageInfo_t* pInfo = static_cast<RequestMessageInfo_t*>(queuedCommand.resultHandlerData);
        _waitForMavlinkMessage(_requestMessageWaitForMessageResultHandler, pInfo, pInfo->msgId, 1000);
    }

    qCDebug(VehicleLog) << "_sendMavCommandAgain sending name:retry" << rawCommandName << _mavCommandRetryCount;
DonLakeFlyer's avatar
 
DonLakeFlyer committed

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;
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        cmd.target_component =  queuedCommand.compId;
        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(),
                                            vehicleLinkManager()->primaryLink()->mavlinkChannel(),
                                            &msg,
                                            &cmd);
    } else {
        mavlink_command_long_t  cmd;

        memset(&cmd, 0, sizeof(cmd));
        cmd.target_system =     _id;
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        cmd.target_component =  queuedCommand.compId;
        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(),
                                             vehicleLinkManager()->primaryLink()->mavlinkChannel(),
    sendMessageOnLinkThreadSafe(vehicleLinkManager()->primaryLink(), msg);
Don Gagne's avatar
Don Gagne committed
}
void Vehicle::_sendNextQueuedMavCommand()
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    if (!_mavCommandQueue.isEmpty()) {
        _mavCommandRetryCount = 0;
        _sendMavCommandAgain();
    }
}

DonLakeFlyer's avatar
DonLakeFlyer committed
void Vehicle::_handleCommandAck(mavlink_message_t& message)
{
    mavlink_command_ack_t ack;
    mavlink_msg_command_ack_decode(&message, &ack);

DonLakeFlyer's avatar
 
DonLakeFlyer committed
    QString rawCommandName  =_toolbox->missionCommandTree()->rawName(static_cast<MAV_CMD>(ack.command));
    qCDebug(VehicleLog) << QStringLiteral("_handleCommandAck command(%1) result(%2)").arg(rawCommandName).arg(QGCMAVLink::mavResultToString(static_cast<MAV_RESULT>(ack.result)));
DonLakeFlyer's avatar
 
DonLakeFlyer committed

    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.isEmpty() && ack.command == _mavCommandQueue.head().command) {
        bool                    sendNextCommand = false;
        MavCommandQueueEntry_t  commandEntry = _mavCommandQueue.head();
DonLakeFlyer's avatar
DonLakeFlyer committed
        _mavCommandAckTimer.stop();

DonLakeFlyer's avatar
 
DonLakeFlyer committed
        if (commandEntry.requestMessage) {
            RequestMessageInfo_t* pInfo = static_cast<RequestMessageInfo_t*>(commandEntry.resultHandlerData);
            pInfo->commandAckReceived = true;
            if (ack.result == MAV_RESULT_ACCEPTED) {
                if (pInfo->messageReceived) {
                    delete pInfo;
                    sendNextCommand = true;
                } else {
                    // We dont set sendNextCommand because we wait for the message wait to complete before sending next message
                    _waitForMavlinkMessageTimeoutActive = true;
                    _waitForMavlinkMessageElapsed.restart();
                }
            } else {
                sendNextCommand = true;
                if (pInfo->messageReceived) {
                    qCWarning(VehicleLog) << "Internal Error: _handleCommandAck for requestMessage with result failure, but message already received";
                } else {
                    _waitForMavlinkMessageClear();
                    (*commandEntry.resultHandler)(commandEntry.resultHandlerData, message.compid, static_cast<MAV_RESULT>(ack.result), false /* noResponsefromVehicle */);
                }
            }
        } else {
            if (commandEntry.resultHandler) {
                (*commandEntry.resultHandler)(commandEntry.resultHandlerData, message.compid, static_cast<MAV_RESULT>(ack.result), false /* noResponsefromVehicle */);
            } else {
                if (commandEntry.showError) {
                    switch (ack.result) {
                    case MAV_RESULT_TEMPORARILY_REJECTED:
                        qgcApp()->showAppMessage(tr("%1 command temporarily rejected").arg(rawCommandName));
                        break;
                    case MAV_RESULT_DENIED:
                        qgcApp()->showAppMessage(tr("%1 command denied").arg(rawCommandName));
                        break;
                    case MAV_RESULT_UNSUPPORTED:
                        qgcApp()->showAppMessage(tr("%1 command not supported").arg(rawCommandName));
                        break;
                    case MAV_RESULT_FAILED:
                        qgcApp()->showAppMessage(tr("%1 command failed").arg(rawCommandName));
                        break;
                    default:
                        // Do nothing
                        break;
                    }
                }
                emit mavCommandResult(_id, message.compid, ack.command, ack.result, false /* noResponsefromVehicle */);
            }
            sendNextCommand = true;
        }

        _mavCommandQueue.dequeue();
        if (sendNextCommand) {
            _sendNextQueuedMavCommand();
        }
    } else {
        qCDebug(VehicleLog) << "_handleCommandAck Ack not in queue" << rawCommandName;
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    }
DonLakeFlyer's avatar
 
DonLakeFlyer committed
}
DonLakeFlyer's avatar
DonLakeFlyer committed

DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::_waitForMavlinkMessage(WaitForMavlinkMessageResultHandler resultHandler, void* resultHandlerData, int messageId, int timeoutMsecs)
{
    qCDebug(VehicleLog) << "_waitForMavlinkMessage msg:timeout" << messageId << timeoutMsecs;
    _waitForMavlinkMessageResultHandler     = resultHandler;
    _waitForMavlinkMessageResultHandlerData = resultHandlerData;
    _waitForMavlinkMessageId                = messageId;
    _waitForMavlinkMessageTimeoutActive     = false;
    _waitForMavlinkMessageTimeoutMsecs      = timeoutMsecs;
}

void Vehicle::_waitForMavlinkMessageClear(void)
{
    qCDebug(VehicleLog) << "_waitForMavlinkMessageClear";
    _waitForMavlinkMessageResultHandler     = nullptr;
    _waitForMavlinkMessageResultHandlerData = nullptr;
    _waitForMavlinkMessageId                = 0;
}

void Vehicle::_waitForMavlinkMessageMessageReceived(const mavlink_message_t& message)
{
    if (_waitForMavlinkMessageId != 0) {
        if (_waitForMavlinkMessageId == message.msgid) {
            WaitForMavlinkMessageResultHandler  resultHandler       = _waitForMavlinkMessageResultHandler;
            void*                               resultHandlerData   = _waitForMavlinkMessageResultHandlerData;
            qCDebug(VehicleLog) << "_waitForMavlinkMessageMessageReceived message received" << _waitForMavlinkMessageId;
            _waitForMavlinkMessageClear();
            (*resultHandler)(resultHandlerData, false /* noResponseFromVehicle */, message);
        } else if (_waitForMavlinkMessageTimeoutActive && _waitForMavlinkMessageElapsed.elapsed() > _waitForMavlinkMessageTimeoutMsecs) {
            WaitForMavlinkMessageResultHandler  resultHandler       = _waitForMavlinkMessageResultHandler;
            void*                               resultHandlerData   = _waitForMavlinkMessageResultHandlerData;
            qCDebug(VehicleLog) << "_waitForMavlinkMessageMessageReceived message timed out" << _waitForMavlinkMessageId;
            _waitForMavlinkMessageClear();
            (*resultHandler)(resultHandlerData, true /* noResponseFromVehicle */, message);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::requestMessage(RequestMessageResultHandler resultHandler, void* resultHandlerData, int compId, int messageId, float param1, float param2, float param3, float param4, float param5)
{
    RequestMessageInfo_t* pInfo = new RequestMessageInfo_t;

DonLakeFlyer's avatar
 
DonLakeFlyer committed
    *pInfo                      = { };
DonLakeFlyer's avatar
 
DonLakeFlyer committed
    pInfo->msgId                = messageId;
    pInfo->compId               = compId;
    pInfo->resultHandler        = resultHandler;
    pInfo->resultHandlerData    = resultHandlerData;

    _sendMavCommandWorker(false,                                    // commandInt
                          true,                                     // requestMessage,
                          false,                                    // showError
                          _requestMessageCmdResultHandler,
                          pInfo,
                          compId,
                          MAV_CMD_REQUEST_MESSAGE,
                          MAV_FRAME_GLOBAL,
                          messageId,
                          param1, param2, param3, param4, param5, 0);
}

void Vehicle::_requestMessageCmdResultHandler(void* resultHandlerData, int /*compId*/, MAV_RESULT result, bool noResponsefromVehicle)
{
    RequestMessageInfo_t* pInfo   = static_cast<RequestMessageInfo_t*>(resultHandlerData);

    pInfo->commandAckReceived = true;
    if (result != MAV_RESULT_ACCEPTED) {
        mavlink_message_t message;
        (*pInfo->resultHandler)(pInfo->resultHandlerData, result,  noResponsefromVehicle ? RequestMessageFailureCommandNotAcked : RequestMessageFailureCommandError, message);
    }
    if (pInfo->messageReceived) {
        delete pInfo;
    }
}

void Vehicle::_requestMessageWaitForMessageResultHandler(void* resultHandlerData, bool noResponsefromVehicle, const mavlink_message_t& message)
{
    RequestMessageInfo_t* pInfo = static_cast<RequestMessageInfo_t*>(resultHandlerData);

    pInfo->messageReceived = true;
    (*pInfo->resultHandler)(pInfo->resultHandlerData, noResponsefromVehicle ? MAV_RESULT_FAILED : MAV_RESULT_ACCEPTED, noResponsefromVehicle ? RequestMessageFailureMessageNotReceived : RequestMessageNoFailure, message);
}

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::_rebootCommandResultHandler(void* resultHandlerData, int /*compId*/, MAV_RESULT commandResult, bool noResponsefromVehicle)
    Vehicle* vehicle = static_cast<Vehicle*>(resultHandlerData);
DonLakeFlyer's avatar
 
DonLakeFlyer committed

    if (commandResult != MAV_RESULT_ACCEPTED) {
        if (noResponsefromVehicle) {
            qCDebug(VehicleLog) << "MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN no response from vehicle";
        } else {
            qCDebug(VehicleLog) << QStringLiteral("MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN error(%1)").arg(commandResult);
        }
        qgcApp()->showAppMessage(tr("Vehicle reboot failed."));
    } else {
        vehicle->closeVehicle();
    }
}

void Vehicle::rebootVehicle()
{
    sendMavCommandWithHandler(_rebootCommandResultHandler, this, _defaultComponentId, MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN, 1);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::startCalibration(Vehicle::CalibrationType calType)
{
    float param1 = 0;
    float param2 = 0;
    float param3 = 0;
    float param4 = 0;
    float param5 = 0;
    float param6 = 0;
    float param7 = 0;

    switch (calType) {
    case CalibrationGyro:
        param1 = 1;
        break;
    case CalibrationMag:
        param2 = 1;
        break;
    case CalibrationRadio:
        param4 = 1;
        break;
    case CalibrationCopyTrims:
        param4 = 2;
        break;
    case CalibrationAccel:
        param5 = 1;
        break;
    case CalibrationLevel:
        param5 = 2;
        break;
    case CalibrationEsc:
        param7 = 1;
        break;
    case CalibrationPX4Airspeed:
        param6 = 1;
        break;
    case CalibrationPX4Pressure:
        param3 = 1;
        break;
    case CalibrationAPMCompassMot:
        param6 = 1;
        break;
    case CalibrationAPMPressureAirspeed:
        param3 = 1;
        break;
    case CalibrationAPMPreFlight:
        param3 = 1; // GroundPressure/Airspeed
        if (multiRotor() || rover()) {
            // Gyro cal for ArduCopter only
            param1 = 1;
        }
    }

    // We can't use sendMavCommand here since we have no idea how long it will be before the command returns a result. This in turn
    // causes the retry logic to break down.
    mavlink_message_t msg;
    mavlink_msg_command_long_pack_chan(_mavlink->getSystemId(),
                                       _mavlink->getComponentId(),
                                       vehicleLinkManager()->primaryLink()->mavlinkChannel(),
DonLakeFlyer's avatar
 
DonLakeFlyer committed
                                       &msg,
                                       id(),
                                       defaultComponentId(),            // target component
                                       MAV_CMD_PREFLIGHT_CALIBRATION,    // command id
                                       0,                                // 0=first transmission of command
                                       param1, param2, param3, param4, param5, param6, param7);
    sendMessageOnLinkThreadSafe(vehicleLinkManager()->primaryLink(), msg);
DonLakeFlyer's avatar
 
DonLakeFlyer committed
}

void Vehicle::stopCalibration(void)
{
    sendMavCommand(defaultComponentId(),    // target component
                   MAV_CMD_PREFLIGHT_CALIBRATION,     // command id
                   true,                              // showError
                   0,                                 // gyro cal
                   0,                                 // mag cal
                   0,                                 // ground pressure
                   0,                                 // radio cal
                   0,                                 // accel cal
                   0,                                 // airspeed cal
                   0);                                // unused
}

DonLakeFlyer's avatar
 
DonLakeFlyer committed
void Vehicle::startUAVCANBusConfig(void)
{
    sendMavCommand(defaultComponentId(),        // target component
                   MAV_CMD_PREFLIGHT_UAVCAN,    // command id
                   true,                        // showError
                   1);                          // start config
}

void Vehicle::stopUAVCANBusConfig(void)
{
    sendMavCommand(defaultComponentId(),        // target component
                   MAV_CMD_PREFLIGHT_UAVCAN,    // command id
                   true,                        // showError
                   0);                          // stop config