bool InputPage::restartNeeded(VehicleConfigurationSource::INPUT_TYPE selectedType)
{
    ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
    UAVObjectManager *uavoManager = pm->getObject<UAVObjectManager>();

    Q_ASSERT(uavoManager);
    HwSettings *hwSettings = HwSettings::GetInstance(uavoManager);
    HwSettings::DataFields data = hwSettings->getData();
    switch (getWizard()->getControllerType()) {
    case SetupWizard::CONTROLLER_CC:
    case SetupWizard::CONTROLLER_CC3D:
    {
        switch (selectedType) {
        case VehicleConfigurationSource::INPUT_PWM:
            return data.CC_RcvrPort != HwSettings::CC_RCVRPORT_PWMNOONESHOT;

        case VehicleConfigurationSource::INPUT_PPM:
            return data.CC_RcvrPort != HwSettings::CC_RCVRPORT_PPMNOONESHOT;

        case VehicleConfigurationSource::INPUT_SBUS:
            return data.CC_MainPort != HwSettings::CC_MAINPORT_SBUS;

        case VehicleConfigurationSource::INPUT_DSM:
            // TODO: Handle all of the DSM types ?? Which is most common?
            return data.CC_MainPort != HwSettings::CC_MAINPORT_DSM;

        default: return true;
        }
        break;
    }
    case SetupWizard::CONTROLLER_REVO:
    case SetupWizard::CONTROLLER_DISCOVERYF4:
    case SetupWizard::CONTROLLER_NANO:
    {
        switch (selectedType) {
        case VehicleConfigurationSource::INPUT_PWM:
            return data.RM_RcvrPort != HwSettings::RM_RCVRPORT_PWM;

        case VehicleConfigurationSource::INPUT_PPM:
            return data.RM_RcvrPort != HwSettings::RM_RCVRPORT_PPM;

        case VehicleConfigurationSource::INPUT_SBUS:
            return data.RM_MainPort != HwSettings::RM_MAINPORT_SBUS;

        case VehicleConfigurationSource::INPUT_SRXL:
            return data.RM_FlexiPort != HwSettings::RM_FLEXIPORT_SRXL;

        case VehicleConfigurationSource::INPUT_DSM:
            // TODO: Handle all of the DSM types ?? Which is most common?
            return data.RM_MainPort != HwSettings::RM_MAINPORT_DSM;

        default: return true;
        }
        break;
    }
    default: return true;
    }
}
/*
 * 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);
}
ConfigCCHWWidget::ConfigCCHWWidget(QWidget *parent) : ConfigTaskWidget(parent)
{
    m_telemetry = new Ui_CC_HW_Widget();
    m_telemetry->setupUi(this);

    ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
    Core::Internal::GeneralSettings *settings = pm->getObject<Core::Internal::GeneralSettings>();
    if (!settings->useExpertMode()) {
        m_telemetry->saveTelemetryToRAM->setVisible(false);
    }


    UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
    int id = utilMngr->getBoardModel();

    switch (id) {
    case 0x0101:
        m_telemetry->label_2->setPixmap(QPixmap(":/uploader/images/deviceID-0101.svg"));
        break;
    case 0x0301:
        m_telemetry->label_2->setPixmap(QPixmap(":/uploader/images/deviceID-0301.svg"));
        break;
    case 0x0401:
        m_telemetry->label_2->setPixmap(QPixmap(":/configgadget/images/coptercontrol.svg"));
        break;
    case 0x0402:
        m_telemetry->label_2->setPixmap(QPixmap(":/configgadget/images/coptercontrol.svg"));
        break;
    case 0x0201:
        m_telemetry->label_2->setPixmap(QPixmap(":/uploader/images/deviceID-0201.svg"));
        break;
    default:
        m_telemetry->label_2->setPixmap(QPixmap(":/configgadget/images/coptercontrol.svg"));
        break;
    }
    addApplySaveButtons(m_telemetry->saveTelemetryToRAM, m_telemetry->saveTelemetryToSD);
    addWidgetBinding("HwSettings", "CC_FlexiPort", m_telemetry->cbFlexi);
    addWidgetBinding("HwSettings", "CC_MainPort", m_telemetry->cbTele);
    addWidgetBinding("HwSettings", "CC_RcvrPort", m_telemetry->cbRcvr);
    addWidgetBinding("HwSettings", "USB_HIDPort", m_telemetry->cbUsbHid);
    addWidgetBinding("HwSettings", "USB_VCPPort", m_telemetry->cbUsbVcp);
    addWidgetBinding("HwSettings", "TelemetrySpeed", m_telemetry->telemetrySpeed);
    addWidgetBinding("HwSettings", "GPSSpeed", m_telemetry->gpsSpeed);
    // Add Gps protocol configuration

    HwSettings *hwSettings = HwSettings::GetInstance(getObjectManager());
    HwSettings::DataFields hwSettingsData = hwSettings->getData();

    if (hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_GPS] != HwSettings::OPTIONALMODULES_ENABLED) {
        m_telemetry->gpsProtocol->setEnabled(false);
        m_telemetry->gpsProtocol->setToolTip(tr("Enable GPS module and reboot the board to be able to select GPS protocol"));
    } else {
        addWidgetBinding("GPSSettings", "DataProtocol", m_telemetry->gpsProtocol);
    }

    addWidgetBinding("HwSettings", "ComUsbBridgeSpeed", m_telemetry->comUsbBridgeSpeed);
    connect(m_telemetry->cchwHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
    enableSaveButtons(false);
    populateWidgets();
    refreshWidgetsValues();
    forceConnectedState();
}
/**
 * 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 *HwSettings::clone(quint32 instID)
{
    HwSettings *obj = new HwSettings();
    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();
}