void EscCalibrationPage::startButtonClicked()
{
    if (!m_isCalibrating) {
        m_isCalibrating = true;
        ui->startButton->setEnabled(false);
        enableButtons(false);
        ui->outputHigh->setEnabled(true);
        ui->outputLow->setEnabled(false);
        ui->nonconnectedLabel->setEnabled(false);
        ui->connectedLabel->setEnabled(true);
        ui->outputLevel->setText(QString(tr("%1 µs")).arg(HIGH_PWM_OUTPUT_PULSE_LENGTH_MICROSECONDS));
        ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
        UAVObjectManager *uavoManager = pm->getObject<UAVObjectManager>();
        Q_ASSERT(uavoManager);
        MixerSettings *mSettings = MixerSettings::GetInstance(uavoManager);
        Q_ASSERT(mSettings);
        QString mixerTypePattern = "Mixer%1Type";

        OutputCalibrationUtil::startOutputCalibration();
        for (quint32 i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
            UAVObjectField *field = mSettings->getField(mixerTypePattern.arg(i + 1));
            Q_ASSERT(field);
            if (field->getValue().toString() == field->getOptions().at(VehicleConfigurationHelper::MIXER_TYPE_MOTOR)) {
                m_outputChannels << i;
            }
        }
        m_outputUtil.startChannelOutput(m_outputChannels, OFF_PWM_OUTPUT_PULSE_LENGTH_MICROSECONDS);
        QThread::msleep(100);
        m_outputUtil.setChannelOutputValue(HIGH_PWM_OUTPUT_PULSE_LENGTH_MICROSECONDS);

        ui->stopButton->setEnabled(true);
    }
}
void VehicleConfigurationHelper::applyMixerConfiguration(mixerChannelSettings channels[])
{
    // Set all mixer data
    MixerSettings *mSettings = MixerSettings::GetInstance(m_uavoManager);

    Q_ASSERT(mSettings);

    // Set Mixer types and values
    QString mixerTypePattern   = "Mixer%1Type";
    QString mixerVectorPattern = "Mixer%1Vector";
    for (int i = 0; i < 10; i++) {
        UAVObjectField *field = mSettings->getField(mixerTypePattern.arg(i + 1));
        Q_ASSERT(field);
        field->setValue(field->getOptions().at(channels[i].type));

        field = mSettings->getField(mixerVectorPattern.arg(i + 1));
        Q_ASSERT(field);
        field->setValue((channels[i].throttle1 * 127) / 100, 0);
        field->setValue((channels[i].throttle2 * 127) / 100, 1);
        field->setValue((channels[i].roll * 127) / 100, 2);
        field->setValue((channels[i].pitch * 127) / 100, 3);
        field->setValue((channels[i].yaw * 127) / 100, 4);
    }

    // Apply updates
    mSettings->setData(mSettings->getData());
    addModifiedObject(mSettings, tr("Writing mixer settings"));
}
/*
 * This overridden function refreshes widgets which have no direct relation
 * to any of UAVObjects. It saves their dirty state first because update comes
 * from UAVObjects, and then restores it. Aftewards it calls base class
 * function to take care of other widgets which were dynamically added.
 */
void ConfigCameraStabilizationWidget::refreshWidgetsValues(UAVObject *obj)
{
    bool dirty = isDirty();

    // Set module enable checkbox from OptionalModules UAVObject item.
    // It needs special processing because ConfigTaskWidget uses TRUE/FALSE
    // for QCheckBox, but OptionalModules uses Enabled/Disabled enum values.
    HwSettings *hwSettings = HwSettings::GetInstance(getObjectManager());
    HwSettings::DataFields hwSettingsData = hwSettings->getData();

    ui->enableCameraStabilization->setChecked(
        hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_CAMERASTAB] == HwSettings::OPTIONALMODULES_ENABLED);

    // Load mixer outputs which are mapped to camera controls
    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();

    // TODO: Need to reformat object so types are an
    // array themselves.  This gets really awkward
    quint8 *mixerTypes[] = {
        &mixerSettingsData.Mixer1Type,
        &mixerSettingsData.Mixer2Type,
        &mixerSettingsData.Mixer3Type,
        &mixerSettingsData.Mixer4Type,
        &mixerSettingsData.Mixer5Type,
        &mixerSettingsData.Mixer6Type,
        &mixerSettingsData.Mixer7Type,
        &mixerSettingsData.Mixer8Type,
        &mixerSettingsData.Mixer9Type,
        &mixerSettingsData.Mixer10Type,
    };
    const int NUM_MIXERS = sizeof(mixerTypes) / sizeof(mixerTypes[0]);

    QComboBox *outputs[] = {
        ui->rollChannel,
        ui->pitchChannel,
        ui->yawChannel
    };
    const int NUM_OUTPUTS = sizeof(outputs) / sizeof(outputs[0]);

    for (int i = 0; i < NUM_OUTPUTS; i++) {
        // Default to none if not found.
        // Then search for any mixer channels set to this
        outputs[i]->setCurrentIndex(0);
        for (int j = 0; j < NUM_MIXERS; j++) {
            if (*mixerTypes[j] == (MixerSettings::MIXER1TYPE_CAMERAROLLORSERVO1 + i) &&
                outputs[i]->currentIndex() != (j + 1)) {
                outputs[i]->setCurrentIndex(j + 1);
            }
        }
    }

    setDirty(dirty);

    ConfigTaskWidget::refreshWidgetsValues(obj);
}
/**
 * Create a clone of this object, a new instance ID must be specified.
 * Do not use this function directly to create new instances, the
 * UAVObjectManager should be used instead.
 */
UAVDataObject* MixerSettings::clone(quint32 instID)
{
    MixerSettings* obj = new MixerSettings();
    obj->initialize(instID, this->getMetaObject());
    return obj;
}
/*
 * This overridden function updates UAVObjects which have no direct relation
 * to any of widgets. Aftewards it calls base class function to take care of
 * other object to widget relations which were dynamically added.
 */
void ConfigCameraStabilizationWidget::updateObjectsFromWidgets()
{
    // Save state of the module enable checkbox first.
    // Do not use setData() member on whole object, if possible, since it triggers
    // unnessesary UAVObect update.
    quint8 enableModule    = ui->enableCameraStabilization->isChecked() ?
                             HwSettings::OPTIONALMODULES_ENABLED : HwSettings::OPTIONALMODULES_DISABLED;
    HwSettings *hwSettings = HwSettings::GetInstance(getObjectManager());

    hwSettings->setOptionalModules(HwSettings::OPTIONALMODULES_CAMERASTAB, enableModule);

    // Update mixer channels which were mapped to camera outputs in case they are
    // not used for other function yet
    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();

    // TODO: Need to reformat object so types are an
    // array themselves.  This gets really awkward
    quint8 *mixerTypes[] = {
        &mixerSettingsData.Mixer1Type,
        &mixerSettingsData.Mixer2Type,
        &mixerSettingsData.Mixer3Type,
        &mixerSettingsData.Mixer4Type,
        &mixerSettingsData.Mixer5Type,
        &mixerSettingsData.Mixer6Type,
        &mixerSettingsData.Mixer7Type,
        &mixerSettingsData.Mixer8Type,
        &mixerSettingsData.Mixer9Type,
        &mixerSettingsData.Mixer10Type,
    };
    const int NUM_MIXERS = sizeof(mixerTypes) / sizeof(mixerTypes[0]);

    QComboBox *outputs[] = {
        ui->rollChannel,
        ui->pitchChannel,
        ui->yawChannel
    };
    const int NUM_OUTPUTS = sizeof(outputs) / sizeof(outputs[0]);

    ui->message->setText("");
    bool widgetUpdated;
    do {
        widgetUpdated = false;

        for (int i = 0; i < NUM_OUTPUTS; i++) {
            // Channel 1 is second entry, so becomes zero
            int mixerNum = outputs[i]->currentIndex() - 1;

            if ((mixerNum >= 0) && // Short circuit in case of none
                (*mixerTypes[mixerNum] != MixerSettings::MIXER1TYPE_DISABLED) &&
                (*mixerTypes[mixerNum] != MixerSettings::MIXER1TYPE_CAMERAROLLORSERVO1 + i)) {
                // If the mixer channel already mapped to something, it should not be
                // used for camera output, we reset it to none
                outputs[i]->setCurrentIndex(0);
                ui->message->setText("One of the channels is already assigned, reverted to none");

                // Loop again or we may have inconsistent widget and UAVObject
                widgetUpdated = true;
            } else {
                // Make sure no other channels have this output set
                for (int j = 0; j < NUM_MIXERS; j++) {
                    if (*mixerTypes[j] == (MixerSettings::MIXER1TYPE_CAMERAROLLORSERVO1 + i)) {
                        *mixerTypes[j] = MixerSettings::MIXER1TYPE_DISABLED;
                    }
                }

                // If this channel is assigned to one of the outputs that is not disabled
                // set it
                if ((mixerNum >= 0) && (mixerNum < NUM_MIXERS)) {
                    *mixerTypes[mixerNum] = MixerSettings::MIXER1TYPE_CAMERAROLLORSERVO1 + i;
                }
            }
        }
    } while (widgetUpdated);

    // FIXME: Should not use setData() to prevent double updates.
    // It should be refactored after the reformatting of MixerSettings UAVObject.
    mixerSettings->setData(mixerSettingsData);

    ConfigTaskWidget::updateObjectsFromWidgets();
}