/**
   Setup steerable ground vehicle.

   Returns False if impossible to create the mixer.
 */
bool ConfigGroundVehicleWidget::setupGroundVehicleCar(QString airframeType)
{
    // Check coherence:
    // Show any config errors in GUI
    if (throwConfigError(airframeType)) {
        return false;
    }

    // Now setup the channels:
    GUIConfigDataUnion config = getConfigData();
    resetActuators(&config);

    config.ground.GroundVehicleThrottle1 = m_aircraft->gvMotor1ChannelBox->currentIndex();
    config.ground.GroundVehicleThrottle2 = m_aircraft->gvMotor2ChannelBox->currentIndex();
    config.ground.GroundVehicleSteering1 = m_aircraft->gvSteering1ChannelBox->currentIndex();
    config.ground.GroundVehicleSteering2 = m_aircraft->gvSteering2ChannelBox->currentIndex();

    setConfigData(config);

    UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
    Q_ASSERT(mixer);
    resetMotorAndServoMixers(mixer);

    int channel = m_aircraft->gvSteering1ChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);

    channel = m_aircraft->gvSteering2ChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);

    channel = m_aircraft->gvMotor1ChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_REVERSABLEMOTOR);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);

    channel = m_aircraft->gvMotor2ChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_REVERSABLEMOTOR);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);

    // Output success message
    m_aircraft->gvStatusLabel->setText("Mixer generated");

    return true;
}
/**
 Setup steerable ground vehicle.
 
 Returns False if impossible to create the mixer.
 */
bool ConfigGroundVehicleWidget::setupGroundVehicleCar(SystemSettings::AirframeTypeOptions airframeType)
{
    // Check coherence:
	//Show any config errors in GUI
    if (throwConfigError(airframeType)) {
		return false;
	}

    // Now setup the channels:
    GUIConfigDataUnion config = GetConfigData();
    ResetActuators(&config);
	
    config.ground.GroundVehicleThrottle1 = m_aircraft->gvMotor1ChannelBox->currentIndex();
    config.ground.GroundVehicleThrottle2 = m_aircraft->gvMotor2ChannelBox->currentIndex();
    config.ground.GroundVehicleSteering1 = m_aircraft->gvSteering1ChannelBox->currentIndex();
    config.ground.GroundVehicleSteering2 = m_aircraft->gvSteering2ChannelBox->currentIndex();

    SetConfigData(config);

    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    Q_ASSERT(mixerSettings);
    resetMixers(mixerSettings);

    int channel = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_SERVO);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW, 127);

    channel = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_SERVO);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW, -127);

    channel = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_MOTOR);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_THROTTLECURVE1, 127);

    channel = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_MOTOR);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_THROTTLECURVE2, 127);

	//Output success message
    m_aircraft->gvStatusLabel->setText("Mixer generated");
	
    return true;
}
/**
   Setup Elevator/Aileron/Rudder airframe.

   If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing

   Returns False if impossible to create the mixer.
 */
bool ConfigFixedWingWidget::setupFrameFixedWing(QString airframeType)
{
    // Check coherence:
    // Show any config errors in GUI
    if (throwConfigError(airframeType)) {
        return false;
    }

    // Now setup the channels:
    GUIConfigDataUnion config = getConfigData();
    resetActuators(&config);

    config.fixedwing.FixedWingPitch1   = m_aircraft->fwElevator1ChannelBox->currentIndex();
    config.fixedwing.FixedWingPitch2   = m_aircraft->fwElevator2ChannelBox->currentIndex();
    config.fixedwing.FixedWingRoll1    = m_aircraft->fwAileron1ChannelBox->currentIndex();
    config.fixedwing.FixedWingRoll2    = m_aircraft->fwAileron2ChannelBox->currentIndex();
    config.fixedwing.FixedWingYaw1     = m_aircraft->fwRudder1ChannelBox->currentIndex();
    config.fixedwing.FixedWingYaw2     = m_aircraft->fwRudder2ChannelBox->currentIndex();
    config.fixedwing.FixedWingThrottle = m_aircraft->fwEngineChannelBox->currentIndex();

    setConfigData(config);

    UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
    Q_ASSERT(mixer);
    resetMotorAndServoMixers(mixer);

    // ... and compute the matrix:
    // In order to make code a bit nicer, we assume:
    // - Channel dropdowns start with 'None', then 0 to 7

    // 1. Assign the servo/motor/none for each channel

    // motor
    int channel = m_aircraft->fwEngineChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_MOTOR);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);

    // rudder
    channel = m_aircraft->fwRudder1ChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);

    // ailerons
    setMixerValue(mixer, "FirstRollServo", m_aircraft->fwAileron1ChannelBox->currentIndex());
    channel = m_aircraft->fwAileron1ChannelBox->currentIndex() - 1;
    if (channel > -1) {
        // Store differential value onboard
        setMixerValue(mixer, "RollDifferential", m_aircraft->elevonSlider3->value());

        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 127);

        channel = m_aircraft->fwAileron2ChannelBox->currentIndex() - 1;
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 127);
    }

    // elevators
    channel = m_aircraft->fwElevator1ChannelBox->currentIndex() - 1;
    if (channel > -1) {
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, 127);

        channel = m_aircraft->fwElevator2ChannelBox->currentIndex() - 1;
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, 127);
    }

    m_aircraft->fwStatusLabel->setText("Mixer generated");

    return true;
}
/**
   Setup VTail
 */
bool ConfigFixedWingWidget::setupFrameVtail(QString airframeType)
{
    // Check coherence:
    // Show any config errors in GUI
    if (throwConfigError(airframeType)) {
        return false;
    }

    GUIConfigDataUnion config = getConfigData();
    resetActuators(&config);

    config.fixedwing.FixedWingPitch1   = m_aircraft->fwElevator1ChannelBox->currentIndex();
    config.fixedwing.FixedWingPitch2   = m_aircraft->fwElevator2ChannelBox->currentIndex();
    config.fixedwing.FixedWingRoll1    = m_aircraft->fwAileron1ChannelBox->currentIndex();
    config.fixedwing.FixedWingRoll2    = m_aircraft->fwAileron2ChannelBox->currentIndex();
    config.fixedwing.FixedWingThrottle = m_aircraft->fwEngineChannelBox->currentIndex();

    setConfigData(config);

    UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
    Q_ASSERT(mixer);
    resetMotorAndServoMixers(mixer);

    // Save the curve:
    // ... and compute the matrix:
    // In order to make code a bit nicer, we assume:
    // - Channel dropdowns start with 'None', then 0 to 7

    // 1. Assign the servo/motor/none for each channel

    double pitch;
    double roll;
    double yaw;

    // motor
    int channel = m_aircraft->fwEngineChannelBox->currentIndex() - 1;
    setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_MOTOR);
    setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);

    // ailerons
    setMixerValue(mixer, "FirstRollServo", m_aircraft->fwAileron1ChannelBox->currentIndex());
    channel = m_aircraft->fwAileron1ChannelBox->currentIndex() - 1;
    if (channel > -1) {
        // Roll mixer value, currently no slider (should be added for Ailerons response ?)
        roll = 127;
        // Store Roll fixed and RollDifferential values onboard
        setMixerValue(mixer, "MixerValueRoll", 100);
        setMixerValue(mixer, "RollDifferential", m_aircraft->elevonSlider3->value());

        // First Aileron (left)
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, roll);

        // Second Aileron (right)
        channel = m_aircraft->fwAileron2ChannelBox->currentIndex() - 1;
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, roll);
    }

    // vtail (pitch / yaw mixing)
    channel = m_aircraft->fwElevator1ChannelBox->currentIndex() - 1;
    if (channel > -1) {
        // Compute mixer absolute values
        pitch = (double)(m_aircraft->elevonSlider2->value() * 1.27);
        yaw   = (double)(m_aircraft->elevonSlider1->value() * 1.27);

        // Store sliders values onboard
        setMixerValue(mixer, "MixerValuePitch", m_aircraft->elevonSlider2->value());
        setMixerValue(mixer, "MixerValueYaw", m_aircraft->elevonSlider1->value());

        // First Vtail servo
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, -pitch);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -yaw);

        // Second Vtail servo
        channel = m_aircraft->fwElevator2ChannelBox->currentIndex() - 1;
        setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, pitch);
        setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -yaw);
    }

    m_aircraft->fwStatusLabel->setText("Mixer generated");
    return true;
}
/**
 Helper function to update the UI widget objects
 */
SystemSettings::AirframeTypeOptions ConfigMultiRotorWidget::updateConfigObjectsFromWidgets()
{
    SystemSettings::AirframeTypeOptions airframeType = SystemSettings::AIRFRAMETYPE_FIXEDWING;
    QList<QString> motorList;

    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    Q_ASSERT(mixerSettings);

    // Curve is also common to all quads:
    setThrottleCurve(mixerSettings, MixerSettings::MIXER1VECTOR_THROTTLECURVE1, m_aircraft->multiThrottleCurve->getCurve() );

    if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_QUADP) {
        airframeType = SystemSettings::AIRFRAMETYPE_QUADP;
        setupQuad(true);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_QUADX) {
        airframeType = SystemSettings::AIRFRAMETYPE_QUADX;
        setupQuad(false);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_HEXA) {
        airframeType = SystemSettings::AIRFRAMETYPE_HEXA;
        setupHexa(true);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_HEXAX) {
        airframeType = SystemSettings::AIRFRAMETYPE_HEXAX;
        setupHexa(false);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_HEXACOAX) {
        airframeType = SystemSettings::AIRFRAMETYPE_HEXACOAX;

        //Show any config errors in GUI
        if (throwConfigError(6)) {
            return airframeType;
        }
        motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
                  << "VTOLMotorS" << "VTOLMotorSE";
        setupMotors(motorList);

        // Motor 1 to 6, Y6 Layout:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  0.5,  1, -1},
            {  0.5,  1,  1},
            {  0.5, -1, -1},
            {  0.5, -1,  1},
            { -1,    0, -1},
            { -1,    0,  1},
            {  0,    0,  0},
            {  0,    0,  0}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTO) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTO;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;

        }
        motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
                  << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
        setupMotors(motorList);
        // Motor 1 to 8:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  1,  0, -1},
            {  1, -1,  1},
            {  0, -1, -1},
            { -1, -1,  1},
            { -1,  0, -1},
            { -1,  1,  1},
            {  0,  1, -1},
            {  1,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTOV) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTOV;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;
        }
        motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
                  << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
        setupMotors(motorList);
        // Motor 1 to 8:
        // IMPORTANT: Assumes evenly spaced engines
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  0.33, -1, -1},
            {  1   , -1,  1},
            { -1   , -1, -1},
            { -0.33, -1,  1},
            { -0.33,  1, -1},
            { -1   ,  1,  1},
            {  1   ,  1, -1},
            {  0.33,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTOCOAXP) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTOCOAXP;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;
        }
        motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
                  << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
        setupMotors(motorList);
        // Motor 1 to 8:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  1,  0, -1},
            {  1,  0,  1},
            {  0, -1, -1},
            {  0, -1,  1},
            { -1,  0, -1},
            { -1,  0,  1},
            {  0,  1, -1},
            {  0,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTOCOAXX) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTOCOAXX;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;
        }
        motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
                  << "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
        setupMotors(motorList);
        // Motor 1 to 8:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  1,  1, -1},
            {  1,  1,  1},
            {  1, -1, -1},
            {  1, -1,  1},
            { -1, -1, -1},
            { -1, -1,  1},
            { -1,  1, -1},
            { -1,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_TRI) {
        airframeType = SystemSettings::AIRFRAMETYPE_TRI;

        //Show any config errors in GUI
        if (throwConfigError(3)) {
            return airframeType;

        }
        if (m_aircraft->triYawChannelBox->currentText() == "None") {
            m_aircraft->mrStatusLabel->setText("<font color='red'>Error: Assign a Yaw channel</font>");
            return airframeType;
        }
        motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
        setupMotors(motorList);

        GUIConfigDataUnion config = GetConfigData();
        config.multi.TRIYaw = m_aircraft->triYawChannelBox->currentIndex();
        SetConfigData(config);


        // Motor 1 to 6, Y6 Layout:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  0.5,  1,  0},
            {  0.5, -1,  0},
            { -1,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0}
        };
        setupMultiRotorMixer(mixer);

        //tell the mixer about tricopter yaw channel

        int channel = m_aircraft->triYawChannelBox->currentIndex()-1;
        if (channel > -1) {
            setMixerType(mixerSettings, channel, MixerSettings::MIXER1TYPE_SERVO);
            setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW, 127);
        }

        m_aircraft->mrStatusLabel->setText(tr("Configuration OK"));

    }

    return airframeType;
}