Skip to content
Snippets Groups Projects
Vehicle.cc 107 KiB
Newer Older
  • Learn to ignore specific revisions
  • Don Gagne's avatar
    Don Gagne committed
    
        _windFactGroup.direction()->setRawValue(wind.direction);
        _windFactGroup.speed()->setRawValue(wind.speed);
        _windFactGroup.verticalSpeed()->setRawValue(wind.speed_z);
    }
    
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::_handleSysStatus(mavlink_message_t& message)
    {
        mavlink_sys_status_t sysStatus;
        mavlink_msg_sys_status_decode(&message, &sysStatus);
    
        if (sysStatus.current_battery == -1) {
            _batteryFactGroup.current()->setRawValue(VehicleBatteryFactGroup::_currentUnavailable);
        } else {
    
            // Current is in Amps, current_battery is 10 * milliamperes (1 = 10 milliampere)
    
            _batteryFactGroup.current()->setRawValue((float)sysStatus.current_battery / 100.0f);
    
    Don Gagne's avatar
    Don Gagne committed
        }
        if (sysStatus.voltage_battery == UINT16_MAX) {
            _batteryFactGroup.voltage()->setRawValue(VehicleBatteryFactGroup::_voltageUnavailable);
        } else {
            _batteryFactGroup.voltage()->setRawValue((double)sysStatus.voltage_battery / 1000.0);
        }
        _batteryFactGroup.percentRemaining()->setRawValue(sysStatus.battery_remaining);
    
        if (sysStatus.battery_remaining > 0) {
            if (sysStatus.battery_remaining < _settingsManager->appSettings()->batteryPercentRemainingAnnounce()->rawValue().toInt() &&
                    sysStatus.battery_remaining < _lastAnnouncedLowBatteryPercent) {
                _say(QString("%1 low battery: %2 percent remaining").arg(_vehicleIdSpeech()).arg(sysStatus.battery_remaining));
            }
    
            _lastAnnouncedLowBatteryPercent = sysStatus.battery_remaining;
    
    
        _onboardControlSensorsPresent = sysStatus.onboard_control_sensors_present;
        _onboardControlSensorsEnabled = sysStatus.onboard_control_sensors_enabled;
        _onboardControlSensorsHealth = sysStatus.onboard_control_sensors_health;
    
        uint32_t newSensorsUnhealthy = _onboardControlSensorsEnabled & ~_onboardControlSensorsHealth;
        if (newSensorsUnhealthy != _onboardControlSensorsUnhealthy) {
            _onboardControlSensorsUnhealthy = newSensorsUnhealthy;
            emit unhealthySensorsChanged();
        }
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    void Vehicle::_handleBatteryStatus(mavlink_message_t& message)
    {
        mavlink_battery_status_t bat_status;
        mavlink_msg_battery_status_decode(&message, &bat_status);
    
        if (bat_status.temperature == INT16_MAX) {
            _batteryFactGroup.temperature()->setRawValue(VehicleBatteryFactGroup::_temperatureUnavailable);
        } else {
            _batteryFactGroup.temperature()->setRawValue((double)bat_status.temperature / 100.0);
        }
        if (bat_status.current_consumed == -1) {
            _batteryFactGroup.mahConsumed()->setRawValue(VehicleBatteryFactGroup::_mahConsumedUnavailable);
        } else {
            _batteryFactGroup.mahConsumed()->setRawValue(bat_status.current_consumed);
        }
    
        int cellCount = 0;
        for (int i=0; i<10; i++) {
            if (bat_status.voltages[i] != UINT16_MAX) {
                cellCount++;
            }
        }
        if (cellCount == 0) {
            cellCount = -1;
        }
    
        _batteryFactGroup.cellCount()->setRawValue(cellCount);
    }
    
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
    void Vehicle::_setHomePosition(QGeoCoordinate& homeCoord)
    {
        if (homeCoord != _homePosition) {
            _homePosition = homeCoord;
            emit homePositionChanged(_homePosition);
        }
    }
    
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::_handleHomePosition(mavlink_message_t& message)
    {
        mavlink_home_position_t homePos;
    
    Don Gagne's avatar
    Don Gagne committed
        mavlink_msg_home_position_decode(&message, &homePos);
    
    Don Gagne's avatar
    Don Gagne committed
    
        QGeoCoordinate newHomePosition (homePos.latitude / 10000000.0,
                                        homePos.longitude / 10000000.0,
                                        homePos.altitude / 1000.0);
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        _setHomePosition(newHomePosition);
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    void Vehicle::_handleHeartbeat(mavlink_message_t& message)
    {
    
        if (message.compid != _defaultComponentId) {
            return;
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
        mavlink_heartbeat_t heartbeat;
    
    Don Gagne's avatar
    Don Gagne committed
        mavlink_msg_heartbeat_decode(&message, &heartbeat);
    
    Don Gagne's avatar
    Don Gagne committed
        bool newArmed = heartbeat.base_mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY;
    
    Don Gagne's avatar
    Don Gagne committed
        if (_armed != newArmed) {
            _armed = newArmed;
            emit armedChanged(_armed);
    
            // We are transitioning to the armed state, begin tracking trajectory points for the map
            if (_armed) {
                _mapTrajectoryStart();
    
                _clearCameraTriggerPoints();
    
            } else {
                _mapTrajectoryStop();
            }
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
        if (heartbeat.base_mode != _base_mode || heartbeat.custom_mode != _custom_mode) {
    
            QString previousFlightMode;
            if (_base_mode != 0 || _custom_mode != 0){
                // Vehicle is initialized with _base_mode=0 and _custom_mode=0. Don't pass this to flightMode() since it will complain about
                // bad modes while unit testing.
                previousFlightMode = flightMode();
            }
    
    Don Gagne's avatar
    Don Gagne committed
            _base_mode = heartbeat.base_mode;
            _custom_mode = heartbeat.custom_mode;
    
            if (previousFlightMode != flightMode()) {
                emit flightModeChanged(flightMode());
            }
    
    void Vehicle::_handleRadioStatus(mavlink_message_t& message)
    {
    
        //-- Process telemetry status message
        mavlink_radio_status_t rstatus;
        mavlink_msg_radio_status_decode(&message, &rstatus);
    
        int rssi    = rstatus.rssi;
        int remrssi = rstatus.remrssi;
    
        int lnoise = (int)(int8_t)rstatus.noise;
        int rnoise = (int)(int8_t)rstatus.remnoise;
    
        //-- 3DR Si1k radio needs rssi fields to be converted to dBm
        if (message.sysid == '3' && message.compid == 'D') {
            /* Per the Si1K datasheet figure 23.25 and SI AN474 code
             * samples the relationship between the RSSI register
             * and received power is as follows:
             *
             *                       10
             * inputPower = rssi * ------ 127
             *                       19
             *
             * Additionally limit to the only realistic range [-120,0] dBm
             */
            rssi    = qMin(qMax(qRound(static_cast<qreal>(rssi)    / 1.9 - 127.0), - 120), 0);
            remrssi = qMin(qMax(qRound(static_cast<qreal>(remrssi) / 1.9 - 127.0), - 120), 0);
    
        } else {
            rssi    = (int)(int8_t)rstatus.rssi;
            remrssi = (int)(int8_t)rstatus.remrssi;
    
        }
        //-- Check for changes
        if(_telemetryLRSSI != rssi) {
            _telemetryLRSSI = rssi;
            emit telemetryLRSSIChanged(_telemetryLRSSI);
        }
        if(_telemetryRRSSI != remrssi) {
            _telemetryRRSSI = remrssi;
            emit telemetryRRSSIChanged(_telemetryRRSSI);
        }
        if(_telemetryRXErrors != rstatus.rxerrors) {
            _telemetryRXErrors = rstatus.rxerrors;
            emit telemetryRXErrorsChanged(_telemetryRXErrors);
        }
        if(_telemetryFixed != rstatus.fixed) {
            _telemetryFixed = rstatus.fixed;
            emit telemetryFixedChanged(_telemetryFixed);
        }
        if(_telemetryTXBuffer != rstatus.txbuf) {
            _telemetryTXBuffer = rstatus.txbuf;
            emit telemetryTXBufferChanged(_telemetryTXBuffer);
        }
    
        if(_telemetryLNoise != lnoise) {
            _telemetryLNoise = lnoise;
    
            emit telemetryLNoiseChanged(_telemetryLNoise);
        }
    
        if(_telemetryRNoise != rnoise) {
            _telemetryRNoise = rnoise;
    
            emit telemetryRNoiseChanged(_telemetryRNoise);
        }
    }
    
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::_handleRCChannels(mavlink_message_t& message)
    {
        mavlink_rc_channels_t channels;
    
        mavlink_msg_rc_channels_decode(&message, &channels);
    
        uint16_t* _rgChannelvalues[cMaxRcChannels] = {
            &channels.chan1_raw,
            &channels.chan2_raw,
            &channels.chan3_raw,
            &channels.chan4_raw,
            &channels.chan5_raw,
            &channels.chan6_raw,
            &channels.chan7_raw,
            &channels.chan8_raw,
            &channels.chan9_raw,
            &channels.chan10_raw,
            &channels.chan11_raw,
            &channels.chan12_raw,
            &channels.chan13_raw,
            &channels.chan14_raw,
            &channels.chan15_raw,
            &channels.chan16_raw,
            &channels.chan17_raw,
            &channels.chan18_raw,
        };
        int pwmValues[cMaxRcChannels];
    
        for (int i=0; i<cMaxRcChannels; i++) {
            uint16_t channelValue = *_rgChannelvalues[i];
    
            if (i < channels.chancount) {
                pwmValues[i] = channelValue == UINT16_MAX ? -1 : channelValue;
            } else {
                pwmValues[i] = -1;
            }
        }
    
        emit remoteControlRSSIChanged(channels.rssi);
        emit rcChannelsChanged(channels.chancount, pwmValues);
    }
    
    void Vehicle::_handleRCChannelsRaw(mavlink_message_t& message)
    {
        // We handle both RC_CHANNLES and RC_CHANNELS_RAW since different firmware will only
        // send one or the other.
    
        mavlink_rc_channels_raw_t channels;
    
        mavlink_msg_rc_channels_raw_decode(&message, &channels);
    
        uint16_t* _rgChannelvalues[cMaxRcChannels] = {
            &channels.chan1_raw,
            &channels.chan2_raw,
            &channels.chan3_raw,
            &channels.chan4_raw,
            &channels.chan5_raw,
            &channels.chan6_raw,
            &channels.chan7_raw,
            &channels.chan8_raw,
        };
    
        int pwmValues[cMaxRcChannels];
        int channelCount = 0;
    
    
    Don Gagne's avatar
    Don Gagne committed
        for (int i=0; i<cMaxRcChannels; i++) {
            pwmValues[i] = -1;
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
        for (int i=0; i<8; i++) {
            uint16_t channelValue = *_rgChannelvalues[i];
    
            if (channelValue == UINT16_MAX) {
                pwmValues[i] = -1;
            } else {
    
    Don Gagne's avatar
    Don Gagne committed
                channelCount = i + 1;
    
    Don Gagne's avatar
    Don Gagne committed
                pwmValues[i] = channelValue;
            }
        }
        for (int i=9; i<18; i++) {
            pwmValues[i] = -1;
        }
    
        emit remoteControlRSSIChanged(channels.rssi);
        emit rcChannelsChanged(channelCount, pwmValues);
    }
    
    
    void Vehicle::_handleScaledPressure(mavlink_message_t& message) {
        mavlink_scaled_pressure_t pressure;
        mavlink_msg_scaled_pressure_decode(&message, &pressure);
        _temperatureFactGroup.temperature1()->setRawValue(pressure.temperature / 100.0);
    }
    
    void Vehicle::_handleScaledPressure2(mavlink_message_t& message) {
        mavlink_scaled_pressure2_t pressure;
        mavlink_msg_scaled_pressure2_decode(&message, &pressure);
        _temperatureFactGroup.temperature2()->setRawValue(pressure.temperature / 100.0);
    }
    
    void Vehicle::_handleScaledPressure3(mavlink_message_t& message) {
        mavlink_scaled_pressure3_t pressure;
        mavlink_msg_scaled_pressure3_decode(&message, &pressure);
        _temperatureFactGroup.temperature3()->setRawValue(pressure.temperature / 100.0);
    }
    
    
    bool Vehicle::_containsLink(LinkInterface* link)
    {
    
    Don Gagne's avatar
    Don Gagne committed
        return _links.contains(link);
    
    }
    
    void Vehicle::_addLink(LinkInterface* link)
    {
        if (!_containsLink(link)) {
            qCDebug(VehicleLog) << "_addLink:" << QString("%1").arg((ulong)link, 0, 16);
    
            _links += link;
            _updatePriorityLink();
    
            connect(_toolbox->linkManager(), &LinkManager::linkInactive, this, &Vehicle::_linkInactiveOrDeleted);
            connect(_toolbox->linkManager(), &LinkManager::linkDeleted, this, &Vehicle::_linkInactiveOrDeleted);
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::_linkInactiveOrDeleted(LinkInterface* link)
    
    Don Gagne's avatar
    Don Gagne committed
        qCDebug(VehicleLog) << "_linkInactiveOrDeleted linkCount" << _links.count();
    
    Don Gagne's avatar
    Don Gagne committed
        _links.removeOne(link);
    
        _updatePriorityLink();
    
    Don Gagne's avatar
    Don Gagne committed
        if (_links.count() == 0 && !_allLinksInactiveSent) {
    
    Don Gagne's avatar
    Don Gagne committed
            qCDebug(VehicleLog) << "All links inactive";
    
    Don Gagne's avatar
    Don Gagne committed
            // Make sure to not send this more than one time
            _allLinksInactiveSent = true;
            emit allLinksInactive(this);
    
    bool Vehicle::sendMessageOnLink(LinkInterface* link, mavlink_message_t message)
    {
        if (!link || !_links.contains(link) || !link->isConnected()) {
            return false;
        }
    
        emit _sendMessageOnLinkOnThread(link, message);
    
        return true;
    }
    
    void Vehicle::_sendMessageOnLink(LinkInterface* link, mavlink_message_t message)
    {
    
        // Make sure this is still a good link
        if (!link || !_links.contains(link) || !link->isConnected()) {
            return;
        }
    
    
    #if 0
        // Leaving in for ease in Mav 2.0 testing
        mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(link->mavlinkChannel());
        qDebug() << "_sendMessageOnLink" << mavlinkStatus << link->mavlinkChannel() << mavlinkStatus->flags << message.magic;
    #endif
    
    
        // Give the plugin a chance to adjust
    
        _firmwarePlugin->adjustOutgoingMavlinkMessage(this, link, &message);
    
    Don Gagne's avatar
    Don Gagne committed
    
        // Write message into buffer, prepending start sign
        uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
        int len = mavlink_msg_to_send_buffer(buffer, &message);
    
        link->writeBytesSafe((const char*)buffer, len);
    
        _messagesSent++;
        emit messagesSentChanged();
    
    void Vehicle::_updatePriorityLink(void)
    
        LinkInterface* newPriorityLink = NULL;
    
    
    #ifndef NO_SERIAL_LINK
    
        // Note that this routine specificallty does not clear _priorityLink when there are no links remaining.
        // By doing this we hold a reference on the last link as the Vehicle shuts down. Thus preventing shutdown
        // ordering NULL pointer crashes where priorityLink() is still called during shutdown sequence.
        for (int i=0; i<_links.count(); i++) {
            LinkInterface* link = _links[i];
    
            if (link->isConnected()) {
                SerialLink* pSerialLink = qobject_cast<SerialLink*>(link);
                if (pSerialLink) {
    
                    LinkConfiguration* config = pSerialLink->getLinkConfiguration();
                    if (config) {
                        SerialConfiguration* pSerialConfig = qobject_cast<SerialConfiguration*>(config);
    
                        if (pSerialConfig && pSerialConfig->usbDirect()) {
    
                            if (_priorityLink.data() != link) {
                                newPriorityLink = link;
                                break;
                            }
                            return;
    
    
        if (!newPriorityLink && !_priorityLink.data() && _links.count()) {
            newPriorityLink = _links[0];
        }
    
        if (newPriorityLink) {
    
            _priorityLink = _toolbox->linkManager()->sharedLinkInterfacePointerForLink(newPriorityLink);
    
    void Vehicle::_updateAttitude(UASInterface*, double roll, double pitch, double yaw, quint64)
    {
    
    Don Gagne's avatar
    Don Gagne committed
            _rollFact.setRawValue(0);
    
    Don Gagne's avatar
    Don Gagne committed
            _rollFact.setRawValue(roll * (180.0 / M_PI));
    
    Don Gagne's avatar
    Don Gagne committed
            _pitchFact.setRawValue(0);
    
    Don Gagne's avatar
    Don Gagne committed
            _pitchFact.setRawValue(pitch * (180.0 / M_PI));
    
    Don Gagne's avatar
    Don Gagne committed
            _headingFact.setRawValue(0);
    
    Don Gagne's avatar
    Don Gagne committed
            yaw = yaw * (180.0 / M_PI);
    
    Mark Whitehorn's avatar
    Mark Whitehorn committed
            if (yaw < 0.0) yaw += 360.0;
            // truncate to integer so widget never displays 360
            _headingFact.setRawValue(trunc(yaw));
    
        }
    }
    
    void Vehicle::_updateAttitude(UASInterface* uas, int, double roll, double pitch, double yaw, quint64 timestamp)
    {
        _updateAttitude(uas, roll, pitch, yaw, timestamp);
    }
    
    
    Don Gagne's avatar
    Don Gagne committed
    int Vehicle::motorCount(void)
    {
        switch (_vehicleType) {
        case MAV_TYPE_HELICOPTER:
            return 1;
        case MAV_TYPE_VTOL_DUOROTOR:
            return 2;
        case MAV_TYPE_TRICOPTER:
            return 3;
        case MAV_TYPE_QUADROTOR:
        case MAV_TYPE_VTOL_QUADROTOR:
            return 4;
        case MAV_TYPE_HEXAROTOR:
            return 6;
        case MAV_TYPE_OCTOROTOR:
            return 8;
        default:
            return -1;
        }
    }
    
    bool Vehicle::coaxialMotors(void)
    {
        return _firmwarePlugin->multiRotorCoaxialMotors(this);
    }
    
    bool Vehicle::xConfigMotors(void)
    {
        return _firmwarePlugin->multiRotorXConfig(this);
    }
    
    
    /*
     * Internal
     */
    
    QString Vehicle::getMavIconColor()
    {
        // TODO: Not using because not only the colors are ghastly, it doesn't respect dark/light palette
        if(_mav)
            return _mav->getColor().name();
        else
            return QString("black");
    }
    
    
    dogmaphobic's avatar
    dogmaphobic committed
    QString Vehicle::formatedMessages()
    {
        QString messages;
    
        foreach(UASMessage* message, _toolbox->uasMessageHandler()->messages()) {
    
    dogmaphobic's avatar
    dogmaphobic committed
            messages += message->getFormatedText();
        }
        return messages;
    }
    
    
    dogmaphobic's avatar
    dogmaphobic committed
    void Vehicle::clearMessages()
    {
    
        _toolbox->uasMessageHandler()->clearMessages();
    
    dogmaphobic's avatar
    dogmaphobic committed
    void Vehicle::_handletextMessageReceived(UASMessage* message)
    {
        if(message)
        {
            _formatedMessage = message->getFormatedText();
            emit formatedMessageChanged();
        }
    }
    
    
    void Vehicle::_handleTextMessage(int newCount)
    {
        // Reset?
        if(!newCount) {
            _currentMessageCount = 0;
            _currentNormalCount  = 0;
            _currentWarningCount = 0;
            _currentErrorCount   = 0;
            _messageCount        = 0;
            _currentMessageType  = MessageNone;
            emit newMessageCountChanged();
            emit messageTypeChanged();
            emit messageCountChanged();
            return;
        }
    
        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();
        }
    }
    
    
    int Vehicle::manualControlReservedButtonCount(void)
    {
        return _firmwarePlugin->manualControlReservedButtonCount();
    }
    
    void Vehicle::_loadSettings(void)
    {
        QSettings settings;
    
        settings.beginGroup(QString(_settingsGroup).arg(_id));
    
        _joystickMode = (JoystickMode_t)settings.value(_joystickModeSettingsKey, JoystickModeRC).toInt(&convertOk);
        if (!convertOk) {
            _joystickMode = JoystickModeRC;
        }
    
        // 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(void)
    {
        QSettings settings;
    
        settings.beginGroup(QString(_settingsGroup).arg(_id));
    
        settings.setValue(_joystickModeSettingsKey, _joystickMode);
    
    
        // 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);
        }
    
    }
    
    int Vehicle::joystickMode(void)
    {
        return _joystickMode;
    }
    
    void Vehicle::setJoystickMode(int mode)
    {
        if (mode < 0 || mode >= JoystickModeMax) {
            qCWarning(VehicleLog) << "Invalid joystick mode" << mode;
            return;
        }
    
        _joystickMode = (JoystickMode_t)mode;
        _saveSettings();
        emit joystickModeChanged(mode);
    }
    
    QStringList Vehicle::joystickModes(void)
    {
        QStringList list;
    
        list << "Normal" << "Attitude" << "Position" << "Force" << "Velocity";
    
    Jacob Walser's avatar
    Jacob Walser committed
    void Vehicle::_activeJoystickChanged(void)
    {
    
    Gus Grubba's avatar
    Gus Grubba committed
        _loadSettings();
        _startJoystick(true);
    
    bool Vehicle::joystickEnabled(void)
    {
        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) {
                if (_joystickEnabled) {
                    joystick->startPolling(this);
                }
            } else {
                joystick->stopPolling();
            }
        }
    }
    
    bool Vehicle::active(void)
    {
        return _active;
    }
    
    void Vehicle::setActive(bool active)
    {
    
        if (_active != active) {
            _active = active;
            emit activeChanged(_active);
        }
    
        _startJoystick(_active);
    }
    
    QGeoCoordinate Vehicle::homePosition(void)
    {
        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);
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    bool Vehicle::flightModeSetAvailable(void)
    {
    
        return _firmwarePlugin->isCapable(this, FirmwarePlugin::SetFlightModeCapability);
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    QStringList Vehicle::flightModes(void)
    {
    
    Daniel Agar's avatar
    Daniel Agar committed
        return _firmwarePlugin->flightModes(this);
    
    Don Gagne's avatar
    Don Gagne committed
    QString Vehicle::flightMode(void) 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);
            sendMessageOnLink(priorityLink(), msg);
    
    Don Gagne's avatar
    Don Gagne committed
        } else {
    
    Don Gagne's avatar
    Don Gagne committed
            qWarning() << "FirmwarePlugin::setFlightMode failed, flightMode:" << flightMode;
    
    Don Gagne's avatar
    Don Gagne committed
        }
    }
    
    bool Vehicle::hilMode(void)
    {
        return _base_mode & MAV_MODE_FLAG_HIL_ENABLED;
    }
    
    void Vehicle::setHilMode(bool hilMode)
    {
        mavlink_message_t msg;
    
        uint8_t newBaseMode = _base_mode & ~MAV_MODE_FLAG_DECODE_POSITION_HIL;
        if (hilMode) {
            newBaseMode |= MAV_MODE_FLAG_HIL_ENABLED;
        }
    
    
        mavlink_msg_set_mode_pack_chan(_mavlink->getSystemId(),
                                       _mavlink->getComponentId(),
                                       priorityLink()->mavlinkChannel(),
                                       &msg,
                                       id(),
                                       newBaseMode,
                                       _custom_mode);
        sendMessageOnLink(priorityLink(), msg);
    
    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);
    
        if (sendMultiple) {
            // We use sendMessageMultiple since we really want these to make it to the vehicle
            sendMessageMultiple(msg);
        } else {
    
            sendMessageOnLink(priorityLink(), msg);
    
    }
    
    void Vehicle::_sendMessageMultipleNext(void)
    {
        if (_nextSendMessageMultipleIndex < _sendMessageMultipleList.count()) {
            qCDebug(VehicleLog) << "_sendMessageMultipleNext:" << _sendMessageMultipleList[_nextSendMessageMultipleIndex].message.msgid;
    
            sendMessageOnLink(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);
    
        qgcApp()->showMessage(tr("Mission transfer failed. Retry transfer. Error: %1").arg(errorMsg));
    
    void Vehicle::_geoFenceManagerError(int errorCode, const QString& errorMsg)
    {
        Q_UNUSED(errorCode);
    
        qgcApp()->showMessage(tr("GeoFence transfer failed. Retry transfer. Error: %1").arg(errorMsg));
    
    }
    
    void Vehicle::_rallyPointManagerError(int errorCode, const QString& errorMsg)
    {
        Q_UNUSED(errorCode);
    
        qgcApp()->showMessage(tr("Rally Point transfer failed. Retry transfer. Error: %1").arg(errorMsg));
    
    void Vehicle::_addNewMapTrajectoryPoint(void)
    {
        if (_mapTrajectoryHaveFirstCoordinate) {
    
            // Keep three minutes of trajectory on mobile due to perf impact of lines
    #ifdef __mobile__
    
            if (_mapTrajectoryList.count() * _mapTrajectoryMsecsBetweenPoints > 3 * 1000 * 60) {
                _mapTrajectoryList.removeAt(0)->deleteLater();
            }
    
    #endif
    
            _mapTrajectoryList.append(new CoordinateVector(_mapTrajectoryLastCoordinate, _coordinate, this));
    
            _flightDistanceFact.setRawValue(_flightDistanceFact.rawValue().toDouble() + _mapTrajectoryLastCoordinate.distanceTo(_coordinate));
    
        }
        _mapTrajectoryHaveFirstCoordinate = true;
    
        _mapTrajectoryLastCoordinate = _coordinate;
    
        _flightTimeFact.setRawValue((double)_flightTimer.elapsed() / 1000.0);
    
    void Vehicle::_clearTrajectoryPoints(void)
    {
        _mapTrajectoryList.clearAndDeleteContents();
    }
    
    void Vehicle::_clearCameraTriggerPoints(void)
    {
        _cameraTriggerPoints.clearAndDeleteContents();
    
    }
    
    void Vehicle::_mapTrajectoryStart(void)
    {
        _mapTrajectoryHaveFirstCoordinate = false;
    
        _clearTrajectoryPoints();
    
        _mapTrajectoryTimer.start();
    
        _flightTimer.start();
    
        _flightDistanceFact.setRawValue(0);
    
        _flightTimeFact.setRawValue(0);
    
    }
    
    void Vehicle::_mapTrajectoryStop()
    {
        _mapTrajectoryTimer.stop();
    }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
    void Vehicle::_startPlanRequest(void)
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        if (_missionManagerInitialRequestSent) {
            return;
        }
    
        if (_parameterManager->parametersReady() && _vehicleCapabilitiesKnown) {
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            qCDebug(VehicleLog) << "_startPlanRequest";
    
            _missionManagerInitialRequestSent = true;
    
            if (_settingsManager->appSettings()->autoLoadMissions()->rawValue().toBool()) {
                QString missionAutoLoadDirPath = _settingsManager->appSettings()->missionSavePath();
                if (!missionAutoLoadDirPath.isEmpty()) {
                    QDir missionAutoLoadDir(missionAutoLoadDirPath);
    
                    QString autoloadFilename = missionAutoLoadDir.absoluteFilePath(tr("AutoLoad%1.%2").arg(_id).arg(AppSettings::planFileExtension));
                    if (QFile(autoloadFilename).exists()) {
    
                        _initialPlanRequestComplete = true; // We aren't going to load from the vehicle, so we are done
    
                        PlanMasterController::sendPlanToVehicle(this, autoloadFilename);
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            _missionManager->loadFromVehicle();
    
        } else {
            if (!_parameterManager->parametersReady()) {
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                qCDebug(VehicleLog) << "Delaying _startPlanRequest due to parameters not ready";
    
            } else if (!_vehicleCapabilitiesKnown) {
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                qCDebug(VehicleLog) << "Delaying _startPlanRequest due to vehicle capabilities not known";
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
    void Vehicle::_missionLoadComplete(void)
    {
        // After the initial mission request completes we ask for the geofence
        if (!_geoFenceManagerInitialRequestSent) {
            _geoFenceManagerInitialRequestSent = true;
    
            if (_geoFenceManager->supported()) {
                qCDebug(VehicleLog) << "_missionLoadComplete requesting GeoFence";
                _geoFenceManager->loadFromVehicle();
            } else {
                qCDebug(VehicleLog) << "_missionLoadComplete GeoFence not supported skipping";
                _geoFenceLoadComplete();
            }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        }
    }
    
    void Vehicle::_geoFenceLoadComplete(void)
    {
        // After geofence request completes we ask for the rally points
        if (!_rallyPointManagerInitialRequestSent) {
            _rallyPointManagerInitialRequestSent = true;
    
            if (_rallyPointManager->supported()) {
                qCDebug(VehicleLog) << "_missionLoadComplete requesting Rally Points";
                _rallyPointManager->loadFromVehicle();
            } else {
                qCDebug(VehicleLog) << "_missionLoadComplete Rally Points not supported skipping";
                _rallyPointLoadComplete();
            }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        }
    }
    
    void Vehicle::_rallyPointLoadComplete(void)
    {
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        qCDebug(VehicleLog) << "_missionLoadComplete _initialPlanRequestComplete = true";
    
        if (!_initialPlanRequestComplete) {
            _initialPlanRequestComplete = true;
    
    Don Gagne's avatar
    Don Gagne committed
            emit initialPlanRequestCompleteChanged(true);
    
    void Vehicle::_parametersReady(bool parametersReady)
    {
        if (parametersReady) {
    
            _setupAutoDisarmSignalling();
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            _startPlanRequest();
    
    Lorenz Meier's avatar
    Lorenz Meier committed
            setJoystickEnabled(_joystickEnabled);
        }
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::disconnectInactiveVehicle(void)
    
    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]);
            }
    
    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)
    {
    
        if (_rcRSSIstore < 0 || _rcRSSIstore > 100) {
            _rcRSSIstore = 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);