Skip to content
Snippets Groups Projects
Vehicle.cc 156 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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;
        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.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;
        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.append(entry);
    
        if (_mavCommandQueue.count() == 1) {
            _mavCommandRetryCount = 0;
            _sendMavCommandAgain();
        }
    }
    
    void Vehicle::_sendMavCommandAgain(void)
    {
    
        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) {
                // We aren't going to get a response back for capabilities, so stop waiting for it before we ask for mission items
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                qCDebug(VehicleLog) << "Vehicle failed to responded to MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES. Setting no capabilities. Starting Plan request.";
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                _setCapabilities(0);
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                _startPlanRequest();
    
            if (queuedCommand.command == MAV_CMD_REQUEST_PROTOCOL_VERSION) {
    
                // We aren't going to get a response back for the protocol version, so assume v1 is all we can do.
                // If the max protocol version is uninitialized, fall back to v1.
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                qCDebug(VehicleLog) << "Vehicle failed to responded to MAV_CMD_REQUEST_PROTOCOL_VERSION. Starting Plan request.";
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                    qCDebug(VehicleLog) << "Setting _maxProtoVersion to 100 since not yet set.";
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                } else {
                    qCDebug(VehicleLog) << "Leaving _maxProtoVersion at current value" << _maxProtoVersion;
    
            emit mavCommandResult(_id, queuedCommand.component, queuedCommand.command, MAV_RESULT_FAILED, true /* noResponsefromVehicle */);
            if (queuedCommand.showError) {
    
                qgcApp()->showMessage(tr("Vehicle did not respond to command: %1").arg(_toolbox->missionCommandTree()->friendlyName(queuedCommand.command)));
    
            }
            _mavCommandQueue.removeFirst();
            _sendNextQueuedMavCommand();
            return;
        }
    
    
        if (_mavCommandRetryCount > 1) {
    
            // We always let AUTOPILOT_CAPABILITIES go through multiple times even if we don't get acks. This is because
            // we really need to get capabilities and version info back over a lossy link.
            if (queuedCommand.command != MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES) {
                if (px4Firmware()) {
                    // Older PX4 firmwares are inconsistent with repect to sending back an Ack from a COMMAND_LONG, hence we can't support retry logic for it.
                    if (_firmwareMajorVersion != versionNotSetValue) {
                        // If no version set assume lastest master dev build, so acks are suppored
                        if (_firmwareMajorVersion <= 1 && _firmwareMinorVersion <= 5 && _firmwarePatchVersion <= 3) {
                            // Acks not supported in this version
                            return;
                        }
                    }
                } else {
                    if (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();
    
    
    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(void)
    {
        if (_mavCommandQueue.count()) {
            _mavCommandRetryCount = 0;
            _sendMavCommandAgain();
        }
    }
    
    
    
    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);
    
        if (ack.command == MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES && ack.result != MAV_RESULT_ACCEPTED) {
            // We aren't going to get a response back for capabilities, so stop waiting for it before we ask for mission items
            qCDebug(VehicleLog) << QStringLiteral("Vehicle responded to MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES with error(%1). Setting no capabilities. Starting Plan request.").arg(ack.result);
            _setCapabilities(0);
        }
    
        if (ack.command == MAV_CMD_REQUEST_PROTOCOL_VERSION && ack.result != MAV_RESULT_ACCEPTED) {
            // The autopilot does not understand the request and consequently is likely handling only
            // MAVLink 1
            qCDebug(VehicleLog) << QStringLiteral("Vehicle responded to MAV_CMD_REQUEST_PROTOCOL_VERSION with error(%1).").arg(ack.result);
            if (_maxProtoVersion == 0) {
                qCDebug(VehicleLog) << "Setting _maxProtoVersion to 100 since not yet set.";
                _setMaxProtoVersion(100);
            } else {
                qCDebug(VehicleLog) << "Leaving _maxProtoVersion at current value" << _maxProtoVersion;
            }
            // FIXME: Is this missing here. I believe it is a bug. Debug to verify. May need to go into Stable.
            //_startPlanRequest();
        }
    
        if (_mavCommandQueue.count() && ack.command == _mavCommandQueue[0].command) {
            _mavCommandAckTimer.stop();
            showError = _mavCommandQueue[0].showError;
            _mavCommandQueue.removeFirst();
        }
    
        emit mavCommandResult(_id, message.compid, ack.command, ack.result, false /* noResponsefromVehicle */);
    
        if (showError) {
            QString commandName = _toolbox->missionCommandTree()->friendlyName((MAV_CMD)ack.command);
    
            switch (ack.result) {
            case MAV_RESULT_TEMPORARILY_REJECTED:
                qgcApp()->showMessage(tr("%1 command temporarily rejected").arg(commandName));
                break;
            case MAV_RESULT_DENIED:
                qgcApp()->showMessage(tr("%1 command denied").arg(commandName));
                break;
            case MAV_RESULT_UNSUPPORTED:
                qgcApp()->showMessage(tr("%1 command not supported").arg(commandName));
                break;
            case MAV_RESULT_FAILED:
                qgcApp()->showMessage(tr("%1 command failed").arg(commandName));
                break;
            default:
                // Do nothing
                break;
            }
        }
    
        _sendNextQueuedMavCommand();
    }
    
    
    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(void)
    {
        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(void) 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;
    
        sendMavCommand(_defaultComponentId, MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN, true, 1.0f);
    
    void Vehicle::setSoloFirmware(bool soloFirmware)
    {
        if (soloFirmware != _soloFirmware) {
            _soloFirmware = soloFirmware;
            emit soloFirmwareChanged(soloFirmware);
        }
    }
    
    
    void Vehicle::motorTest(int motor, int percent)
    
        sendMavCommand(_defaultComponentId, MAV_CMD_DO_MOTOR_TEST, true, motor, MOTOR_TEST_THROTTLE_PERCENT, percent, 0, 0, MOTOR_TEST_ORDER_BOARD);
    
    QString Vehicle::brandImageIndoor(void) const
    
        return _firmwarePlugin->brandImageIndoor(this);
    }
    
    QString Vehicle::brandImageOutdoor(void) const
    {
        return _firmwarePlugin->brandImageOutdoor(this);
    
    QStringList Vehicle::unhealthySensors(void) 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";
        }
    }
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::triggerCamera(void)
    {
    
    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::_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)
    
    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);
    
    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());
    
        _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(void) const
    {
        return _firmwarePlugin->missionFlightMode();
    }
    
    
    QString Vehicle::pauseFlightMode(void) const
    {
        return _firmwarePlugin->pauseFlightMode();
    }
    
    
    QString Vehicle::rtlFlightMode(void) const
    {
        return _firmwarePlugin->rtlFlightMode();
    }
    
    
    QString Vehicle::landFlightMode(void) const
    {
        return _firmwarePlugin->landFlightMode();
    }
    
    
    QString Vehicle::takeControlFlightMode(void) const
    {
        return _firmwarePlugin->takeControlFlightMode();
    }
    
    
    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();
    }
    
    
    const QVariantList& Vehicle::toolBarIndicators()
    
    {
        if(_firmwarePlugin) {
            return _firmwarePlugin->toolBarIndicators(this);
        }
        static QVariantList emptyList;
        return emptyList;
    }
    
    
    Gus Grubba's avatar
    Gus Grubba committed
    const QVariantList& Vehicle::staticCameraList(void) const
    
    {
        if (_firmwarePlugin) {
            return _firmwarePlugin->cameraList(this);
        }
        static QVariantList emptyList;
        return emptyList;
    }
    
    
    bool Vehicle::vehicleYawsToNextWaypointInMission(void) const
    {
        return _firmwarePlugin->vehicleYawsToNextWaypointInMission(this);
    }
    
    void Vehicle::_setupAutoDisarmSignalling(void)
    {
        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(void)
    {
        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)
    {
        mavlink_adsb_vehicle_t adsbVehicle;
    
    Don Gagne's avatar
    Don Gagne committed
        static const int maxTimeSinceLastSeen = 15;
    
    
        mavlink_msg_adsb_vehicle_decode(&message, &adsbVehicle);
        if (adsbVehicle.flags | ADSB_FLAGS_VALID_COORDS) {
            if (_adsbICAOMap.contains(adsbVehicle.ICAO_address)) {
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                if (adsbVehicle.tslc > maxTimeSinceLastSeen) {
                    ADSBVehicle* vehicle = _adsbICAOMap[adsbVehicle.ICAO_address];
                    _adsbVehicles.removeOne(vehicle);
                    _adsbICAOMap.remove(adsbVehicle.ICAO_address);
                    vehicle->deleteLater();
                } else {
    
    Don Gagne's avatar
    Don Gagne committed
                    _adsbICAOMap[adsbVehicle.ICAO_address]->update(adsbVehicle);
    
    Don Gagne's avatar
    Don Gagne committed
            } else if (adsbVehicle.tslc <= maxTimeSinceLastSeen) {
    
                ADSBVehicle* vehicle = new ADSBVehicle(adsbVehicle, this);
                _adsbICAOMap[adsbVehicle.ICAO_address] = vehicle;
                _adsbVehicles.append(vehicle);
            }
        }
    }
    
    
    void Vehicle::_updateDistanceToHome(void)
    {
        if (coordinate().isValid() && homePosition().isValid()) {
            _distanceToHomeFact.setRawValue(coordinate().distanceTo(homePosition()));
        } else {
            _distanceToHomeFact.setRawValue(qQNaN());
        }
    }
    
    
    void Vehicle::_updateHobbsMeter(void)
    {
        _hobbsFact.setRawValue(hobbsMeter());
    }
    
    
    Don Gagne's avatar
    Don Gagne committed
    void Vehicle::forceInitialPlanRequestComplete(void)
    {
        _initialPlanRequestComplete = true;
        emit initialPlanRequestCompleteChanged(true);
    }
    
    void Vehicle::sendPlan(QString planFile)
    {
        PlanMasterController::sendPlanToVehicle(this, planFile);
    }
    
    
    QString Vehicle::hobbsMeter()
    {
        static const char* HOOBS_HI = "LND_FLIGHT_T_HI";
        static const char* HOOBS_LO = "LND_FLIGHT_T_LO";
        //-- TODO: Does this exist on non PX4?
        if (_parameterManager->parameterExists(FactSystem::defaultComponentId, HOOBS_HI) &&
    
                _parameterManager->parameterExists(FactSystem::defaultComponentId, HOOBS_LO)) {
    
            Fact* factHi = _parameterManager->getParameter(FactSystem::defaultComponentId, HOOBS_HI);
            Fact* factLo = _parameterManager->getParameter(FactSystem::defaultComponentId, HOOBS_LO);
    
            uint64_t hobbsTimeSeconds = ((uint64_t)factHi->rawValue().toUInt() << 32 | (uint64_t)factLo->rawValue().toUInt()) / 1000000;
    
            int hours   = hobbsTimeSeconds / 3600;
            int minutes = (hobbsTimeSeconds % 3600) / 60;
            int seconds = hobbsTimeSeconds % 60;
            QString timeStr;
            timeStr.sprintf("%04d:%02d:%02d", hours, minutes, seconds);
    
            qCDebug(VehicleLog) << "Hobbs Meter:" << timeStr << "(" << factHi->rawValue().toUInt() << factLo->rawValue().toUInt() << ")";
    
            return timeStr;
        }
        return QString("0000:00:00");
    }
    
    void Vehicle::_vehicleParamLoaded(bool ready)
    {
        //-- TODO: This seems silly but can you think of a better
        //   way to update this?
        if(ready) {
            emit hobbsMeterChanged();
        }
    }
    
    
    void Vehicle::_updateHighLatencyLink(bool sendCommand)
    
        if (_priorityLink->highLatency() != _highLatencyLink) {
            _highLatencyLink = _priorityLink->highLatency();
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            _mavCommandAckTimer.setInterval(_highLatencyLink ? _mavCommandAckTimeoutMSecsHighLatency : _mavCommandAckTimeoutMSecs);
    
            emit highLatencyLinkChanged(_highLatencyLink);
    
    acfloria's avatar
    acfloria committed
                sendMavCommand(defaultComponentId(),
                               MAV_CMD_CONTROL_HIGH_LATENCY,
                               true,
                               _highLatencyLink ? 1.0f : 0.0f); // request start/stop transmitting over high latency telemetry
    
    Gus Grubba's avatar
    Gus Grubba committed
    void Vehicle::_trafficUpdate(bool alert, QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading)
    
        // qDebug() << "traffic update:" << traffic_id << vehicle_id << heading << location;
        // TODO: filter based on minimum altitude?
        if (_trafficVehicleMap.contains(traffic_id)) {
    
    Gus Grubba's avatar
    Gus Grubba committed
            _trafficVehicleMap[traffic_id]->update(alert, location, heading);
    
    Gus Grubba's avatar
    Gus Grubba committed
            ADSBVehicle* vehicle = new ADSBVehicle(location, heading, alert, this);
    
            _trafficVehicleMap[traffic_id] = vehicle;
            _adsbVehicles.append(vehicle);
        }
    
    }
    
    void Vehicle::_adsbTimerTimeout()
    {
        // TODO: take into account _adsbICAOMap as well? Needs to be tested, especially the timeout
    
        for (auto it = _trafficVehicleMap.begin(); it != _trafficVehicleMap.end();) {
            if (it.value()->expired()) {
                _adsbVehicles.removeOne(it.value());
                delete it.value();
                it = _trafficVehicleMap.erase(it);
            } else {
                ++it;
            }
        }
    }
    
    void Vehicle::_mavlinkMessageStatus(int uasId, uint64_t totalSent, uint64_t totalReceived, uint64_t totalLoss, float lossPercent)
    {
        if(uasId == _id) {
            _mavlinkSentCount       = totalSent;
            _mavlinkReceivedCount   = totalReceived;
            _mavlinkLossCount       = totalLoss;
            _mavlinkLossPercent     = lossPercent;
            emit mavlinkStatusChanged();
        }
    }
    
    
    //-----------------------------------------------------------------------------
    //-----------------------------------------------------------------------------
    
    
    const char* VehicleBatteryFactGroup::_voltageFactName =                     "voltage";
    const char* VehicleBatteryFactGroup::_percentRemainingFactName =            "percentRemaining";
    const char* VehicleBatteryFactGroup::_mahConsumedFactName =                 "mahConsumed";
    const char* VehicleBatteryFactGroup::_currentFactName =                     "current";
    const char* VehicleBatteryFactGroup::_temperatureFactName =                 "temperature";
    const char* VehicleBatteryFactGroup::_cellCountFactName =                   "cellCount";
    
    const char* VehicleBatteryFactGroup::_instantPowerFactName =                "instantPower";
    
    const char* VehicleBatteryFactGroup::_timeRemainingFactName =               "timeRemaining";
    const char* VehicleBatteryFactGroup::_chargeStateFactName =                 "chargeState";
    
    
    const char* VehicleBatteryFactGroup::_settingsGroup =                       "Vehicle.battery";
    
    const double VehicleBatteryFactGroup::_voltageUnavailable =           -1.0;
    const int    VehicleBatteryFactGroup::_percentRemainingUnavailable =  -1;
    const int    VehicleBatteryFactGroup::_mahConsumedUnavailable =       -1;
    const int    VehicleBatteryFactGroup::_currentUnavailable =           -1;
    const double VehicleBatteryFactGroup::_temperatureUnavailable =       -1.0;
    const int    VehicleBatteryFactGroup::_cellCountUnavailable =         -1.0;
    
    const double VehicleBatteryFactGroup::_instantPowerUnavailable =      -1.0;
    
    Don Gagne's avatar
    Don Gagne committed
    VehicleBatteryFactGroup::VehicleBatteryFactGroup(QObject* parent)
        : FactGroup(1000, ":/json/Vehicle/BatteryFact.json", parent)
    
        , _voltageFact                  (0, _voltageFactName,                   FactMetaData::valueTypeDouble)
        , _percentRemainingFact         (0, _percentRemainingFactName,          FactMetaData::valueTypeInt32)
        , _mahConsumedFact              (0, _mahConsumedFactName,               FactMetaData::valueTypeInt32)
    
    Don Gagne's avatar
    Don Gagne committed
        , _currentFact                  (0, _currentFactName,                   FactMetaData::valueTypeFloat)
    
        , _temperatureFact              (0, _temperatureFactName,               FactMetaData::valueTypeDouble)
        , _cellCountFact                (0, _cellCountFactName,                 FactMetaData::valueTypeInt32)
    
        , _instantPowerFact             (0, _instantPowerFactName,              FactMetaData::valueTypeFloat)
    
        , _timeRemainingFact            (0, _timeRemainingFactName,             FactMetaData::valueTypeInt32)
        , _chargeStateFact              (0, _chargeStateFactName,               FactMetaData::valueTypeUint8)
    
        _addFact(&_voltageFact,                 _voltageFactName);
        _addFact(&_percentRemainingFact,        _percentRemainingFactName);
        _addFact(&_mahConsumedFact,             _mahConsumedFactName);
        _addFact(&_currentFact,                 _currentFactName);
        _addFact(&_temperatureFact,             _temperatureFactName);
        _addFact(&_cellCountFact,               _cellCountFactName);
    
        _addFact(&_instantPowerFact,            _instantPowerFactName);
    
        _addFact(&_timeRemainingFact,           _timeRemainingFactName);
        _addFact(&_chargeStateFact,             _chargeStateFactName);
    
    Don Gagne's avatar
    Don Gagne committed
    
        // Start out as not available
        _voltageFact.setRawValue            (_voltageUnavailable);
        _percentRemainingFact.setRawValue   (_percentRemainingUnavailable);
        _mahConsumedFact.setRawValue        (_mahConsumedUnavailable);
        _currentFact.setRawValue            (_currentUnavailable);
        _temperatureFact.setRawValue        (_temperatureUnavailable);
        _cellCountFact.setRawValue          (_cellCountUnavailable);
    
        _instantPowerFact.setRawValue       (_instantPowerUnavailable);
    
    const char* VehicleWindFactGroup::_directionFactName =      "direction";
    const char* VehicleWindFactGroup::_speedFactName =          "speed";
    const char* VehicleWindFactGroup::_verticalSpeedFactName =  "verticalSpeed";
    
    
    Don Gagne's avatar
    Don Gagne committed
    VehicleWindFactGroup::VehicleWindFactGroup(QObject* parent)
        : FactGroup(1000, ":/json/Vehicle/WindFact.json", parent)
        , _directionFact    (0, _directionFactName,     FactMetaData::valueTypeDouble)
        , _speedFact        (0, _speedFactName,         FactMetaData::valueTypeDouble)
        , _verticalSpeedFact(0, _verticalSpeedFactName, FactMetaData::valueTypeDouble)
    {
        _addFact(&_directionFact,       _directionFactName);
        _addFact(&_speedFact,           _speedFactName);
        _addFact(&_verticalSpeedFact,   _verticalSpeedFactName);
    
        // Start out as not available "--.--"
        _directionFact.setRawValue      (std::numeric_limits<float>::quiet_NaN());
        _speedFact.setRawValue          (std::numeric_limits<float>::quiet_NaN());
        _verticalSpeedFact.setRawValue  (std::numeric_limits<float>::quiet_NaN());
    }
    
    
    const char* VehicleVibrationFactGroup::_xAxisFactName =      "xAxis";
    const char* VehicleVibrationFactGroup::_yAxisFactName =      "yAxis";
    const char* VehicleVibrationFactGroup::_zAxisFactName =      "zAxis";
    const char* VehicleVibrationFactGroup::_clipCount1FactName = "clipCount1";
    const char* VehicleVibrationFactGroup::_clipCount2FactName = "clipCount2";
    const char* VehicleVibrationFactGroup::_clipCount3FactName = "clipCount3";
    
    
    VehicleVibrationFactGroup::VehicleVibrationFactGroup(QObject* parent)
        : FactGroup(1000, ":/json/Vehicle/VibrationFact.json", parent)
        , _xAxisFact        (0, _xAxisFactName,         FactMetaData::valueTypeDouble)
        , _yAxisFact        (0, _yAxisFactName,         FactMetaData::valueTypeDouble)
        , _zAxisFact        (0, _zAxisFactName,         FactMetaData::valueTypeDouble)
        , _clipCount1Fact   (0, _clipCount1FactName,    FactMetaData::valueTypeUint32)
        , _clipCount2Fact   (0, _clipCount2FactName,    FactMetaData::valueTypeUint32)
        , _clipCount3Fact   (0, _clipCount3FactName,    FactMetaData::valueTypeUint32)
    {
        _addFact(&_xAxisFact,       _xAxisFactName);
        _addFact(&_yAxisFact,       _yAxisFactName);
        _addFact(&_zAxisFact,       _zAxisFactName);
        _addFact(&_clipCount1Fact,  _clipCount1FactName);
        _addFact(&_clipCount2Fact,  _clipCount2FactName);
        _addFact(&_clipCount3Fact,  _clipCount3FactName);
    
        // Start out as not available "--.--"
        _xAxisFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _yAxisFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _zAxisFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    }
    
    
    const char* VehicleTemperatureFactGroup::_temperature1FactName =      "temperature1";
    const char* VehicleTemperatureFactGroup::_temperature2FactName =      "temperature2";
    const char* VehicleTemperatureFactGroup::_temperature3FactName =      "temperature3";
    
    VehicleTemperatureFactGroup::VehicleTemperatureFactGroup(QObject* parent)
        : FactGroup(1000, ":/json/Vehicle/TemperatureFact.json", parent)
        , _temperature1Fact    (0, _temperature1FactName,     FactMetaData::valueTypeDouble)
        , _temperature2Fact    (0, _temperature2FactName,     FactMetaData::valueTypeDouble)
        , _temperature3Fact    (0, _temperature3FactName,     FactMetaData::valueTypeDouble)
    {
        _addFact(&_temperature1Fact,       _temperature1FactName);
        _addFact(&_temperature2Fact,       _temperature2FactName);
        _addFact(&_temperature3Fact,       _temperature3FactName);
    
        // Start out as not available "--.--"
        _temperature1Fact.setRawValue      (std::numeric_limits<float>::quiet_NaN());
        _temperature2Fact.setRawValue      (std::numeric_limits<float>::quiet_NaN());
        _temperature3Fact.setRawValue      (std::numeric_limits<float>::quiet_NaN());
    }
    
    dheideman's avatar
    dheideman committed
    
    const char* VehicleClockFactGroup::_currentTimeFactName = "currentTime";
    const char* VehicleClockFactGroup::_currentDateFactName = "currentDate";
    
    VehicleClockFactGroup::VehicleClockFactGroup(QObject* parent)
        : FactGroup(1000, ":/json/Vehicle/ClockFact.json", parent)
        , _currentTimeFact  (0, _currentTimeFactName,    FactMetaData::valueTypeString)
        , _currentDateFact  (0, _currentDateFactName,    FactMetaData::valueTypeString)
    {
        _addFact(&_currentTimeFact, _currentTimeFactName);
        _addFact(&_currentDateFact, _currentDateFactName);
    
        // Start out as not available "--.--"
        _currentTimeFact.setRawValue    (std::numeric_limits<float>::quiet_NaN());
        _currentDateFact.setRawValue    (std::numeric_limits<float>::quiet_NaN());
    }
    
    void VehicleClockFactGroup::_updateAllValues(void)
    {
        _currentTimeFact.setRawValue(QTime::currentTime().toString());
        _currentDateFact.setRawValue(QDateTime::currentDateTime().toString(QLocale::system().dateFormat(QLocale::ShortFormat)));
    
        FactGroup::_updateAllValues();
    }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
    
    const char* VehicleSetpointFactGroup::_rollFactName =       "roll";
    const char* VehicleSetpointFactGroup::_pitchFactName =      "pitch";
    const char* VehicleSetpointFactGroup::_yawFactName =        "yaw";
    const char* VehicleSetpointFactGroup::_rollRateFactName =   "rollRate";
    const char* VehicleSetpointFactGroup::_pitchRateFactName =  "pitchRate";
    const char* VehicleSetpointFactGroup::_yawRateFactName =    "yawRate";
    
    VehicleSetpointFactGroup::VehicleSetpointFactGroup(QObject* parent)
        : FactGroup     (1000, ":/json/Vehicle/SetpointFact.json", parent)
        , _rollFact     (0, _rollFactName,      FactMetaData::valueTypeDouble)
        , _pitchFact    (0, _pitchFactName,     FactMetaData::valueTypeDouble)
        , _yawFact      (0, _yawFactName,       FactMetaData::valueTypeDouble)
        , _rollRateFact (0, _rollRateFactName,  FactMetaData::valueTypeDouble)
        , _pitchRateFact(0, _pitchRateFactName, FactMetaData::valueTypeDouble)
        , _yawRateFact  (0, _yawRateFactName,   FactMetaData::valueTypeDouble)
    {
        _addFact(&_rollFact,        _rollFactName);
        _addFact(&_pitchFact,       _pitchFactName);
        _addFact(&_yawFact,         _yawFactName);
        _addFact(&_rollRateFact,    _rollRateFactName);
        _addFact(&_pitchRateFact,   _pitchRateFactName);
        _addFact(&_yawRateFact,     _yawRateFactName);
    
        // Start out as not available "--.--"
        _rollFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _pitchFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _yawFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _rollRateFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _pitchRateFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _yawRateFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    }
    
    
    const char* VehicleDistanceSensorFactGroup::_rotationNoneFactName =     "rotationNone";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw45FactName =    "rotationYaw45";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw90FactName =    "rotationYaw90";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw135FactName =   "rotationYaw135";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw180FactName =   "rotationYaw180";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw225FactName =   "rotationYaw225";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw270FactName =   "rotationYaw270";
    
    const char* VehicleDistanceSensorFactGroup::_rotationYaw315FactName =   "rotationYaw315";
    const char* VehicleDistanceSensorFactGroup::_rotationPitch90FactName =  "rotationPitch90";
    const char* VehicleDistanceSensorFactGroup::_rotationPitch270FactName = "rotationPitch270";
    
    
    VehicleDistanceSensorFactGroup::VehicleDistanceSensorFactGroup(QObject* parent)
        : FactGroup             (1000, ":/json/Vehicle/DistanceSensorFact.json", parent)
        , _rotationNoneFact     (0, _rotationNoneFactName,      FactMetaData::valueTypeDouble)
    
        , _rotationYaw45Fact    (0, _rotationYaw45FactName,     FactMetaData::valueTypeDouble)
    
        , _rotationYaw90Fact    (0, _rotationYaw90FactName,     FactMetaData::valueTypeDouble)
    
        , _rotationYaw135Fact   (0, _rotationYaw135FactName,    FactMetaData::valueTypeDouble)
    
        , _rotationYaw180Fact   (0, _rotationYaw180FactName,    FactMetaData::valueTypeDouble)
    
        , _rotationYaw225Fact   (0, _rotationYaw225FactName,    FactMetaData::valueTypeDouble)
    
        , _rotationYaw270Fact   (0, _rotationYaw270FactName,    FactMetaData::valueTypeDouble)
    
        , _rotationYaw315Fact   (0, _rotationYaw315FactName,    FactMetaData::valueTypeDouble)
        , _rotationPitch90Fact  (0, _rotationPitch90FactName,   FactMetaData::valueTypeDouble)
        , _rotationPitch270Fact (0, _rotationPitch270FactName,  FactMetaData::valueTypeDouble)
        , _idSet                (false)
        , _id                   (0)
    {
        _addFact(&_rotationNoneFact,        _rotationNoneFactName);
        _addFact(&_rotationYaw45Fact,       _rotationYaw45FactName);
        _addFact(&_rotationYaw90Fact,       _rotationYaw90FactName);
        _addFact(&_rotationYaw135Fact,      _rotationYaw135FactName);
        _addFact(&_rotationYaw180Fact,      _rotationYaw180FactName);
        _addFact(&_rotationYaw225Fact,      _rotationYaw225FactName);
        _addFact(&_rotationYaw270Fact,      _rotationYaw270FactName);
        _addFact(&_rotationYaw315Fact,      _rotationYaw315FactName);
        _addFact(&_rotationPitch90Fact,     _rotationPitch90FactName);
        _addFact(&_rotationPitch270Fact,    _rotationPitch270FactName);
    
    
        // Start out as not available "--.--"
        _rotationNoneFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
        _rotationYaw45Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _rotationYaw135Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
        _rotationYaw90Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _rotationYaw180Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
        _rotationYaw225Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
        _rotationYaw270Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
        _rotationPitch90Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
        _rotationPitch270Fact.setRawValue(std::numeric_limits<float>::quiet_NaN());
    
    
    const char* VehicleEstimatorStatusFactGroup::_goodAttitudeEstimateFactName =        "goodAttitudeEsimate";
    const char* VehicleEstimatorStatusFactGroup::_goodHorizVelEstimateFactName =        "goodHorizVelEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodVertVelEstimateFactName =         "goodVertVelEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodHorizPosRelEstimateFactName =     "goodHorizPosRelEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodHorizPosAbsEstimateFactName =     "goodHorizPosAbsEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodVertPosAbsEstimateFactName =      "goodVertPosAbsEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodVertPosAGLEstimateFactName =      "goodVertPosAGLEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodConstPosModeEstimateFactName =    "goodConstPosModeEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodPredHorizPosRelEstimateFactName = "goodPredHorizPosRelEstimate";
    const char* VehicleEstimatorStatusFactGroup::_goodPredHorizPosAbsEstimateFactName = "goodPredHorizPosAbsEstimate";
    const char* VehicleEstimatorStatusFactGroup::_gpsGlitchFactName =                   "gpsGlitch";
    const char* VehicleEstimatorStatusFactGroup::_accelErrorFactName =                  "accelError";
    const char* VehicleEstimatorStatusFactGroup::_velRatioFactName =                    "velRatio";
    const char* VehicleEstimatorStatusFactGroup::_horizPosRatioFactName =               "horizPosRatio";
    const char* VehicleEstimatorStatusFactGroup::_vertPosRatioFactName =                "vertPosRatio";
    const char* VehicleEstimatorStatusFactGroup::_magRatioFactName =                    "magRatio";
    const char* VehicleEstimatorStatusFactGroup::_haglRatioFactName =                   "haglRatio";
    const char* VehicleEstimatorStatusFactGroup::_tasRatioFactName =                    "tasRatio";
    const char* VehicleEstimatorStatusFactGroup::_horizPosAccuracyFactName =            "horizPosAccuracy";
    const char* VehicleEstimatorStatusFactGroup::_vertPosAccuracyFactName =             "vertPosAccuracy";
    
    VehicleEstimatorStatusFactGroup::VehicleEstimatorStatusFactGroup(QObject* parent)
        : FactGroup                         (500, ":/json/Vehicle/EstimatorStatusFactGroup.json", parent)
        , _goodAttitudeEstimateFact         (0, _goodAttitudeEstimateFactName,          FactMetaData::valueTypeBool)
        , _goodHorizVelEstimateFact         (0, _goodHorizVelEstimateFactName,          FactMetaData::valueTypeBool)
        , _goodVertVelEstimateFact          (0, _goodVertVelEstimateFactName,           FactMetaData::valueTypeBool)
        , _goodHorizPosRelEstimateFact      (0, _goodHorizPosRelEstimateFactName,       FactMetaData::valueTypeBool)
        , _goodHorizPosAbsEstimateFact      (0, _goodHorizPosAbsEstimateFactName,       FactMetaData::valueTypeBool)
        , _goodVertPosAbsEstimateFact       (0, _goodVertPosAbsEstimateFactName,        FactMetaData::valueTypeBool)
        , _goodVertPosAGLEstimateFact       (0, _goodVertPosAGLEstimateFactName,        FactMetaData::valueTypeBool)
        , _goodConstPosModeEstimateFact     (0, _goodConstPosModeEstimateFactName,      FactMetaData::valueTypeBool)
        , _goodPredHorizPosRelEstimateFact  (0, _goodPredHorizPosRelEstimateFactName,   FactMetaData::valueTypeBool)
        , _goodPredHorizPosAbsEstimateFact  (0, _goodPredHorizPosAbsEstimateFactName,   FactMetaData::valueTypeBool)
        , _gpsGlitchFact                    (0, _gpsGlitchFactName,                     FactMetaData::valueTypeBool)
        , _accelErrorFact                   (0, _accelErrorFactName,                    FactMetaData::valueTypeBool)
        , _velRatioFact                     (0, _velRatioFactName,                      FactMetaData::valueTypeFloat)
        , _horizPosRatioFact                (0, _horizPosRatioFactName,                 FactMetaData::valueTypeFloat)
        , _vertPosRatioFact                 (0, _vertPosRatioFactName,                  FactMetaData::valueTypeFloat)
        , _magRatioFact                     (0, _magRatioFactName,                      FactMetaData::valueTypeFloat)
        , _haglRatioFact                    (0, _haglRatioFactName,                     FactMetaData::valueTypeFloat)
        , _tasRatioFact                     (0, _tasRatioFactName,                      FactMetaData::valueTypeFloat)
        , _horizPosAccuracyFact             (0, _horizPosAccuracyFactName,              FactMetaData::valueTypeFloat)
        , _vertPosAccuracyFact              (0, _vertPosAccuracyFactName,               FactMetaData::valueTypeFloat)
    {
        _addFact(&_goodAttitudeEstimateFact,        _goodAttitudeEstimateFactName);
        _addFact(&_goodHorizVelEstimateFact,        _goodHorizVelEstimateFactName);
        _addFact(&_goodVertVelEstimateFact,         _goodVertVelEstimateFactName);
        _addFact(&_goodHorizPosRelEstimateFact,     _goodHorizPosRelEstimateFactName);
        _addFact(&_goodHorizPosAbsEstimateFact,     _goodHorizPosAbsEstimateFactName);
        _addFact(&_goodVertPosAbsEstimateFact,      _goodVertPosAbsEstimateFactName);
        _addFact(&_goodVertPosAGLEstimateFact,      _goodVertPosAGLEstimateFactName);
        _addFact(&_goodConstPosModeEstimateFact,    _goodConstPosModeEstimateFactName);
        _addFact(&_goodPredHorizPosRelEstimateFact, _goodPredHorizPosRelEstimateFactName);
        _addFact(&_goodPredHorizPosAbsEstimateFact, _goodPredHorizPosAbsEstimateFactName);
        _addFact(&_gpsGlitchFact,                   _gpsGlitchFactName);
        _addFact(&_accelErrorFact,                  _accelErrorFactName);
        _addFact(&_velRatioFact,                    _velRatioFactName);
        _addFact(&_horizPosRatioFact,               _horizPosRatioFactName);
        _addFact(&_vertPosRatioFact,                _vertPosRatioFactName);
        _addFact(&_magRatioFact,                    _magRatioFactName);
        _addFact(&_haglRatioFact,                   _haglRatioFactName);
        _addFact(&_tasRatioFact,                    _tasRatioFactName);
        _addFact(&_horizPosAccuracyFact,            _horizPosAccuracyFactName);
        _addFact(&_vertPosAccuracyFact,             _vertPosAccuracyFactName);
    }