<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "makestep.h"
#include "ui_makestep.h"

#include "qt4project.h"
#include "qt4target.h"
#include "qt4buildconfiguration.h"
#include "qt4projectmanagerconstants.h"
#include "qtparser.h"

#include <projectexplorer/toolchain.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcprocess.h>

#include <QtCore/QDir>
#include <QtCore/QFileInfo>

using ExtensionSystem::PluginManager;
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;

namespace {
const char * const MAKESTEP_BS_ID("Qt4ProjectManager.MakeStep");

const char * const MAKE_ARGUMENTS_KEY("Qt4ProjectManager.MakeStep.MakeArguments");
const char * const MAKE_COMMAND_KEY("Qt4ProjectManager.MakeStep.MakeCommand");
const char * const CLEAN_KEY("Qt4ProjectManager.MakeStep.Clean");
}

MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl) :
    AbstractProcessStep(bsl, QLatin1String(MAKESTEP_BS_ID)),
    m_clean(false)
{
    ctor();
}

MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, MakeStep *bs) :
    AbstractProcessStep(bsl, bs),
    m_clean(bs->m_clean),
    m_userArgs(bs->m_userArgs),
    m_makeCmd(bs->m_makeCmd)
{
    ctor();
}

MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, const QString &id) :
    AbstractProcessStep(bsl, id),
    m_clean(false)
{
    ctor();
}

void MakeStep::ctor()
{
    setDefaultDisplayName(tr("Make", "Qt4 MakeStep display name."));
}

MakeStep::~MakeStep()
{
}

Qt4BuildConfiguration *MakeStep::qt4BuildConfiguration() const
{
    return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
}

void MakeStep::setClean(bool clean)
{
    m_clean = clean;
}

bool MakeStep::isClean() const
{
    return m_clean;
}

QVariantMap MakeStep::toMap() const
{
    QVariantMap map(ProjectExplorer::AbstractProcessStep::toMap());
    map.insert(QLatin1String(MAKE_ARGUMENTS_KEY), m_userArgs);
    map.insert(QLatin1String(MAKE_COMMAND_KEY), m_makeCmd);
    map.insert(QLatin1String(CLEAN_KEY), m_clean);
    return map;
}

bool MakeStep::fromMap(const QVariantMap &map)
{
    m_makeCmd = map.value(QLatin1String(MAKE_COMMAND_KEY)).toString();
    m_userArgs = map.value(QLatin1String(MAKE_ARGUMENTS_KEY)).toString();
    m_clean = map.value(QLatin1String(CLEAN_KEY)).toBool();

    return ProjectExplorer::AbstractProcessStep::fromMap(map);
}

bool MakeStep::init()
{
    Qt4BuildConfiguration *bc = qt4BuildConfiguration();

    m_tasks.clear();
    if (!bc->toolChain()) {
        m_tasks.append(ProjectExplorer::Task(ProjectExplorer::Task::Error,
                                             tr("Qt Creator needs a tool chain set up to build. Please configure a tool chain in Project mode."),
                                             QString(), -1,
                                             QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
    }

    ProjectExplorer::ProcessParameters *pp = processParameters();
    pp->setMacroExpander(bc->macroExpander());

    Utils::Environment environment = bc->environment();
    pp->setEnvironment(environment);

    QString workingDirectory;
    if (bc->subNodeBuild())
        workingDirectory = bc->subNodeBuild()->buildDir();
    else
        workingDirectory = bc->buildDirectory();
    pp->setWorkingDirectory(workingDirectory);

    QString makeCmd = bc->makeCommand();
    if (!m_makeCmd.isEmpty())
        makeCmd = m_makeCmd;
    pp->setCommand(makeCmd);

    // If we are cleaning, then make can fail with a error code, but that doesn't mean
    // we should stop the clean queue
    // That is mostly so that rebuild works on a already clean project
    setIgnoreReturnValue(m_clean);

    QString args;

    ProjectExplorer::ToolChain *toolchain = bc->toolChain();

    if (bc->subNodeBuild()) {
        QString makefile = bc->subNodeBuild()->makefile();
        if(!makefile.isEmpty()) {
            Utils::QtcProcess::addArg(&args, QLatin1String("-f"));
            Utils::QtcProcess::addArg(&args, makefile);
            m_makeFileToCheck = QDir(workingDirectory).filePath(makefile);
        } else {
            m_makeFileToCheck = QDir(workingDirectory).filePath("Makefile");
        }
    } else {
        if (!bc->makefile().isEmpty()) {
            Utils::QtcProcess::addArg(&args, QLatin1String("-f"));
            Utils::QtcProcess::addArg(&args, bc->makefile());
            m_makeFileToCheck = QDir(workingDirectory).filePath(bc->makefile());
        } else {
            m_makeFileToCheck = QDir(workingDirectory).filePath("Makefile");
        }
    }

    Utils::QtcProcess::addArgs(&args, m_userArgs);

    if (!isClean()) {
        if (!bc->defaultMakeTarget().isEmpty())
            Utils::QtcProcess::addArg(&args, bc->defaultMakeTarget());
    }
    // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
    // absolute file path
    // FIXME doing this without the user having a way to override this is rather bad
    // so we only do it for unix and if the user didn't override the make command
    // but for now this is the least invasive change
    if (toolchain
            && toolchain->targetAbi().binaryFormat() != ProjectExplorer::Abi::PEFormat
            && m_makeCmd.isEmpty())
        Utils::QtcProcess::addArg(&args, QLatin1String("-w"));

    setEnabled(true);
    pp->setArguments(args);

    ProjectExplorer::IOutputParser *parser = bc->qtVersion()->createOutputParser();
    Q_ASSERT(parser);
    parser->appendOutputParser(new QtParser);
    if (toolchain)
        parser->appendOutputParser(toolchain->outputParser());

    parser->setWorkingDirectory(workingDirectory);

    setOutputParser(parser);

    return AbstractProcessStep::init();
}

void MakeStep::run(QFutureInterface<bool> & fi)
{
    if (qt4BuildConfiguration()->qt4Target()->qt4Project()->rootProjectNode()->projectType() == ScriptTemplate) {
        fi.reportResult(true);
        return;
    }

    if (!QFileInfo(m_makeFileToCheck).exists()) {
        if (!m_clean)
            emit addOutput(tr("Makefile not found. Please check your build settings"), BuildStep::MessageOutput);
        fi.reportResult(m_clean);
        return;
    }

    // Warn on common error conditions:
    bool canContinue = true;
    foreach (const ProjectExplorer::Task &t, m_tasks) {
        addTask(t);
        if (t.type == ProjectExplorer::Task::Error)
            canContinue = false;
    }
    if (!canContinue) {
        emit addOutput(tr("Configuration is faulty, please check the Build Issues view for details."), BuildStep::MessageOutput);
        fi.reportResult(false);
        return;
    }

    AbstractProcessStep::run(fi);
}

bool MakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
    // Symbian does retun 0, even on failed makes! So we check for fatal make errors here.
    if (outputParser() && outputParser()->hasFatalErrors())
        return false;

    return AbstractProcessStep::processSucceeded(exitCode, status);
}

bool MakeStep::immutable() const
{
    return false;
}

ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
{
    return new MakeStepConfigWidget(this);
}

QString MakeStep::userArguments()
{
    return m_userArgs;
}

void MakeStep::setUserArguments(const QString &arguments)
{
    m_userArgs = arguments;
    emit userArgumentsChanged();
}

MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
    : BuildStepConfigWidget(), m_ui(new Ui::MakeStep), m_makeStep(makeStep), m_ignoreChange(false)
{
    m_ui->setupUi(this);

    m_ui->makePathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
    m_ui->makePathChooser->setBaseDirectory(Utils::PathChooser::homePath());

    connect(m_ui->makePathChooser, SIGNAL(changed(QString)),
            this, SLOT(makeEdited()));
    connect(m_ui->makeArgumentsLineEdit, SIGNAL(textEdited(QString)),
            this, SLOT(makeArgumentsLineEdited()));

    connect(makeStep, SIGNAL(userArgumentsChanged()),
            this, SLOT(userArgumentsChanged()));
    connect(makeStep->buildConfiguration(), SIGNAL(buildDirectoryChanged()),
            this, SLOT(updateDetails()));

    connect(makeStep->qt4BuildConfiguration(), SIGNAL(qtVersionChanged()),
            this, SLOT(qtVersionChanged()));

    connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
            this, SLOT(updateMakeOverrideLabel()));
    connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
            this, SLOT(updateDetails()));
}

MakeStepConfigWidget::~MakeStepConfigWidget()
{
    delete m_ui;
}

void MakeStepConfigWidget::qtVersionChanged()
{
    updateMakeOverrideLabel();
    updateDetails();
}

void MakeStepConfigWidget::updateMakeOverrideLabel()
{
    Qt4BuildConfiguration *qt4bc = m_makeStep->qt4BuildConfiguration();
    m_ui->makeLabel->setText(tr("Override %1:").arg(qt4bc->makeCommand()));
}

void MakeStepConfigWidget::updateDetails()
{
    Qt4BuildConfiguration *bc = m_makeStep->qt4BuildConfiguration();

    ProjectExplorer::ProcessParameters param;
    param.setMacroExpander(bc->macroExpander());
    param.setWorkingDirectory(bc->buildDirectory());
    param.setEnvironment(bc->environment());
    QString makeCmd = bc->makeCommand();
    if (!m_makeStep->m_makeCmd.isEmpty())
        makeCmd = m_makeStep->m_makeCmd;
    param.setCommand(makeCmd);
    if (param.commandMissing()) {
        m_summaryText = tr("<b>Make:</b> %1 not found in the environment.").arg(makeCmd);
        emit updateSummary();
        return;
    }

    QString args = m_makeStep->userArguments();
    if (!m_makeStep->isClean()) {
        if (!bc->defaultMakeTarget().isEmpty())
            Utils::QtcProcess::addArg(&args, bc->defaultMakeTarget());
    }
    // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
    // absolute file path
    // FIXME doing this without the user having a way to override this is rather bad
    // so we only do it for unix and if the user didn't override the make command
    // but for now this is the least invasive change
    ProjectExplorer::ToolChain *toolChain = bc->toolChain();
    if (toolChain
        && toolChain->targetAbi().binaryFormat() != ProjectExplorer::Abi::PEFormat
        && m_makeStep->m_makeCmd.isEmpty())
        Utils::QtcProcess::addArg(&args, QLatin1String("-w"));
    param.setArguments(args);
    m_summaryText = param.summaryInWorkdir(displayName());
    emit updateSummary();
}

QString MakeStepConfigWidget::summaryText() const
{
    return m_summaryText;
}

QString MakeStepConfigWidget::displayName() const
{
    return m_makeStep->displayName();
}

void MakeStepConfigWidget::userArgumentsChanged()
{
    if (m_ignoreChange)
        return;
    m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
    updateDetails();
}

void MakeStepConfigWidget::init()
{
    updateMakeOverrideLabel();

    const QString &makeCmd = m_makeStep->m_makeCmd;
    m_ui->makePathChooser->setPath(makeCmd);

    m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
    updateDetails();
}

void MakeStepConfigWidget::makeEdited()
{
    m_makeStep->m_makeCmd = m_ui->makePathChooser->rawPath();
    updateDetails();
}

void MakeStepConfigWidget::makeArgumentsLineEdited()
{
    m_ignoreChange = true;
    m_makeStep->setUserArguments(m_ui->makeArgumentsLineEdit->text());
    m_ignoreChange = false;
    updateDetails();
}

///
// MakeStepFactory
///

MakeStepFactory::MakeStepFactory(QObject *parent) :
    ProjectExplorer::IBuildStepFactory(parent)
{
}

MakeStepFactory::~MakeStepFactory()
{
}

bool MakeStepFactory::canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const
{
    if (parent->target()->project()->id() != QLatin1String(Constants::QT4PROJECT_ID))
        return false;
    return (id == QLatin1String(MAKESTEP_BS_ID));
}

ProjectExplorer::BuildStep *MakeStepFactory::create(ProjectExplorer::BuildStepList *parent, const QString &id)
{
    if (!canCreate(parent, id))
        return 0;
    return new MakeStep(parent);
}

bool MakeStepFactory::canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const
{
    return canCreate(parent, source->id());
}

ProjectExplorer::BuildStep *MakeStepFactory::clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source)
{
    if (!canClone(parent, source))
        return 0;
    return new MakeStep(parent, static_cast<MakeStep *>(source));
}

bool MakeStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const
{
    QString id(ProjectExplorer::idFromMap(map));
    return canCreate(parent, id);
}

ProjectExplorer::BuildStep *MakeStepFactory::restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map)
{
    if (!canRestore(parent, map))
        return 0;
    MakeStep *bs(new MakeStep(parent));
    if (bs->fromMap(map))
        return bs;
    delete bs;
    return 0;
}

QStringList MakeStepFactory::availableCreationIds(ProjectExplorer::BuildStepList *parent) const
{
    if (parent->target()->project()->id() == QLatin1String(Constants::QT4PROJECT_ID))
        return QStringList() << QLatin1String(MAKESTEP_BS_ID);
    return QStringList();
}

QString MakeStepFactory::displayNameForId(const QString &id) const
{
    if (id == QLatin1String(MAKESTEP_BS_ID))
        return tr("Make");
    return QString();
}
<commit_msg>Update makestep on toolchain changes<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "makestep.h"
#include "ui_makestep.h"

#include "qt4project.h"
#include "qt4target.h"
#include "qt4buildconfiguration.h"
#include "qt4projectmanagerconstants.h"
#include "qtparser.h"

#include <projectexplorer/toolchain.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcprocess.h>

#include <QtCore/QDir>
#include <QtCore/QFileInfo>

using ExtensionSystem::PluginManager;
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;

namespace {
const char * const MAKESTEP_BS_ID("Qt4ProjectManager.MakeStep");

const char * const MAKE_ARGUMENTS_KEY("Qt4ProjectManager.MakeStep.MakeArguments");
const char * const MAKE_COMMAND_KEY("Qt4ProjectManager.MakeStep.MakeCommand");
const char * const CLEAN_KEY("Qt4ProjectManager.MakeStep.Clean");
}

MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl) :
    AbstractProcessStep(bsl, QLatin1String(MAKESTEP_BS_ID)),
    m_clean(false)
{
    ctor();
}

MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, MakeStep *bs) :
    AbstractProcessStep(bsl, bs),
    m_clean(bs->m_clean),
    m_userArgs(bs->m_userArgs),
    m_makeCmd(bs->m_makeCmd)
{
    ctor();
}

MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, const QString &id) :
    AbstractProcessStep(bsl, id),
    m_clean(false)
{
    ctor();
}

void MakeStep::ctor()
{
    setDefaultDisplayName(tr("Make", "Qt4 MakeStep display name."));
}

MakeStep::~MakeStep()
{
}

Qt4BuildConfiguration *MakeStep::qt4BuildConfiguration() const
{
    return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
}

void MakeStep::setClean(bool clean)
{
    m_clean = clean;
}

bool MakeStep::isClean() const
{
    return m_clean;
}

QVariantMap MakeStep::toMap() const
{
    QVariantMap map(ProjectExplorer::AbstractProcessStep::toMap());
    map.insert(QLatin1String(MAKE_ARGUMENTS_KEY), m_userArgs);
    map.insert(QLatin1String(MAKE_COMMAND_KEY), m_makeCmd);
    map.insert(QLatin1String(CLEAN_KEY), m_clean);
    return map;
}

bool MakeStep::fromMap(const QVariantMap &map)
{
    m_makeCmd = map.value(QLatin1String(MAKE_COMMAND_KEY)).toString();
    m_userArgs = map.value(QLatin1String(MAKE_ARGUMENTS_KEY)).toString();
    m_clean = map.value(QLatin1String(CLEAN_KEY)).toBool();

    return ProjectExplorer::AbstractProcessStep::fromMap(map);
}

bool MakeStep::init()
{
    Qt4BuildConfiguration *bc = qt4BuildConfiguration();

    m_tasks.clear();
    if (!bc->toolChain()) {
        m_tasks.append(ProjectExplorer::Task(ProjectExplorer::Task::Error,
                                             tr("Qt Creator needs a tool chain set up to build. Please configure a tool chain in Project mode."),
                                             QString(), -1,
                                             QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
    }

    ProjectExplorer::ProcessParameters *pp = processParameters();
    pp->setMacroExpander(bc->macroExpander());

    Utils::Environment environment = bc->environment();
    pp->setEnvironment(environment);

    QString workingDirectory;
    if (bc->subNodeBuild())
        workingDirectory = bc->subNodeBuild()->buildDir();
    else
        workingDirectory = bc->buildDirectory();
    pp->setWorkingDirectory(workingDirectory);

    QString makeCmd = bc->makeCommand();
    if (!m_makeCmd.isEmpty())
        makeCmd = m_makeCmd;
    pp->setCommand(makeCmd);

    // If we are cleaning, then make can fail with a error code, but that doesn't mean
    // we should stop the clean queue
    // That is mostly so that rebuild works on a already clean project
    setIgnoreReturnValue(m_clean);

    QString args;

    ProjectExplorer::ToolChain *toolchain = bc->toolChain();

    if (bc->subNodeBuild()) {
        QString makefile = bc->subNodeBuild()->makefile();
        if(!makefile.isEmpty()) {
            Utils::QtcProcess::addArg(&args, QLatin1String("-f"));
            Utils::QtcProcess::addArg(&args, makefile);
            m_makeFileToCheck = QDir(workingDirectory).filePath(makefile);
        } else {
            m_makeFileToCheck = QDir(workingDirectory).filePath("Makefile");
        }
    } else {
        if (!bc->makefile().isEmpty()) {
            Utils::QtcProcess::addArg(&args, QLatin1String("-f"));
            Utils::QtcProcess::addArg(&args, bc->makefile());
            m_makeFileToCheck = QDir(workingDirectory).filePath(bc->makefile());
        } else {
            m_makeFileToCheck = QDir(workingDirectory).filePath("Makefile");
        }
    }

    Utils::QtcProcess::addArgs(&args, m_userArgs);

    if (!isClean()) {
        if (!bc->defaultMakeTarget().isEmpty())
            Utils::QtcProcess::addArg(&args, bc->defaultMakeTarget());
    }
    // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
    // absolute file path
    // FIXME doing this without the user having a way to override this is rather bad
    // so we only do it for unix and if the user didn't override the make command
    // but for now this is the least invasive change
    if (toolchain
            && toolchain->targetAbi().binaryFormat() != ProjectExplorer::Abi::PEFormat
            && m_makeCmd.isEmpty())
        Utils::QtcProcess::addArg(&args, QLatin1String("-w"));

    setEnabled(true);
    pp->setArguments(args);

    ProjectExplorer::IOutputParser *parser = bc->qtVersion()->createOutputParser();
    Q_ASSERT(parser);
    parser->appendOutputParser(new QtParser);
    if (toolchain)
        parser->appendOutputParser(toolchain->outputParser());

    parser->setWorkingDirectory(workingDirectory);

    setOutputParser(parser);

    return AbstractProcessStep::init();
}

void MakeStep::run(QFutureInterface<bool> & fi)
{
    if (qt4BuildConfiguration()->qt4Target()->qt4Project()->rootProjectNode()->projectType() == ScriptTemplate) {
        fi.reportResult(true);
        return;
    }

    if (!QFileInfo(m_makeFileToCheck).exists()) {
        if (!m_clean)
            emit addOutput(tr("Makefile not found. Please check your build settings"), BuildStep::MessageOutput);
        fi.reportResult(m_clean);
        return;
    }

    // Warn on common error conditions:
    bool canContinue = true;
    foreach (const ProjectExplorer::Task &t, m_tasks) {
        addTask(t);
        if (t.type == ProjectExplorer::Task::Error)
            canContinue = false;
    }
    if (!canContinue) {
        emit addOutput(tr("Configuration is faulty, please check the Build Issues view for details."), BuildStep::MessageOutput);
        fi.reportResult(false);
        return;
    }

    AbstractProcessStep::run(fi);
}

bool MakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
    // Symbian does retun 0, even on failed makes! So we check for fatal make errors here.
    if (outputParser() && outputParser()->hasFatalErrors())
        return false;

    return AbstractProcessStep::processSucceeded(exitCode, status);
}

bool MakeStep::immutable() const
{
    return false;
}

ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
{
    return new MakeStepConfigWidget(this);
}

QString MakeStep::userArguments()
{
    return m_userArgs;
}

void MakeStep::setUserArguments(const QString &arguments)
{
    m_userArgs = arguments;
    emit userArgumentsChanged();
}

MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
    : BuildStepConfigWidget(), m_ui(new Ui::MakeStep), m_makeStep(makeStep), m_ignoreChange(false)
{
    m_ui->setupUi(this);

    m_ui->makePathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
    m_ui->makePathChooser->setBaseDirectory(Utils::PathChooser::homePath());

    connect(m_ui->makePathChooser, SIGNAL(changed(QString)),
            this, SLOT(makeEdited()));
    connect(m_ui->makeArgumentsLineEdit, SIGNAL(textEdited(QString)),
            this, SLOT(makeArgumentsLineEdited()));

    connect(makeStep, SIGNAL(userArgumentsChanged()),
            this, SLOT(userArgumentsChanged()));
    connect(makeStep->buildConfiguration(), SIGNAL(buildDirectoryChanged()),
            this, SLOT(updateDetails()));
    connect(makeStep->buildConfiguration(), SIGNAL(toolChainChanged()),
            this, SLOT(updateDetails()));

    connect(makeStep->qt4BuildConfiguration(), SIGNAL(qtVersionChanged()),
            this, SLOT(qtVersionChanged()));

    connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
            this, SLOT(updateMakeOverrideLabel()));
    connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
            this, SLOT(updateDetails()));
}

MakeStepConfigWidget::~MakeStepConfigWidget()
{
    delete m_ui;
}

void MakeStepConfigWidget::qtVersionChanged()
{
    updateMakeOverrideLabel();
    updateDetails();
}

void MakeStepConfigWidget::updateMakeOverrideLabel()
{
    Qt4BuildConfiguration *qt4bc = m_makeStep->qt4BuildConfiguration();
    m_ui->makeLabel->setText(tr("Override %1:").arg(qt4bc->makeCommand()));
}

void MakeStepConfigWidget::updateDetails()
{
    Qt4BuildConfiguration *bc = m_makeStep->qt4BuildConfiguration();

    ProjectExplorer::ProcessParameters param;
    param.setMacroExpander(bc->macroExpander());
    param.setWorkingDirectory(bc->buildDirectory());
    param.setEnvironment(bc->environment());
    QString makeCmd = bc->makeCommand();
    if (!m_makeStep->m_makeCmd.isEmpty())
        makeCmd = m_makeStep->m_makeCmd;
    param.setCommand(makeCmd);
    if (param.commandMissing()) {
        m_summaryText = tr("<b>Make:</b> %1 not found in the environment.").arg(makeCmd);
        emit updateSummary();
        return;
    }

    QString args = m_makeStep->userArguments();
    if (!m_makeStep->isClean()) {
        if (!bc->defaultMakeTarget().isEmpty())
            Utils::QtcProcess::addArg(&args, bc->defaultMakeTarget());
    }
    // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
    // absolute file path
    // FIXME doing this without the user having a way to override this is rather bad
    // so we only do it for unix and if the user didn't override the make command
    // but for now this is the least invasive change
    ProjectExplorer::ToolChain *toolChain = bc->toolChain();
    if (toolChain
        && toolChain->targetAbi().binaryFormat() != ProjectExplorer::Abi::PEFormat
        && m_makeStep->m_makeCmd.isEmpty())
        Utils::QtcProcess::addArg(&args, QLatin1String("-w"));
    param.setArguments(args);
    m_summaryText = param.summaryInWorkdir(displayName());
    emit updateSummary();
}

QString MakeStepConfigWidget::summaryText() const
{
    return m_summaryText;
}

QString MakeStepConfigWidget::displayName() const
{
    return m_makeStep->displayName();
}

void MakeStepConfigWidget::userArgumentsChanged()
{
    if (m_ignoreChange)
        return;
    m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
    updateDetails();
}

void MakeStepConfigWidget::init()
{
    updateMakeOverrideLabel();

    const QString &makeCmd = m_makeStep->m_makeCmd;
    m_ui->makePathChooser->setPath(makeCmd);

    m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
    updateDetails();
}

void MakeStepConfigWidget::makeEdited()
{
    m_makeStep->m_makeCmd = m_ui->makePathChooser->rawPath();
    updateDetails();
}

void MakeStepConfigWidget::makeArgumentsLineEdited()
{
    m_ignoreChange = true;
    m_makeStep->setUserArguments(m_ui->makeArgumentsLineEdit->text());
    m_ignoreChange = false;
    updateDetails();
}

///
// MakeStepFactory
///

MakeStepFactory::MakeStepFactory(QObject *parent) :
    ProjectExplorer::IBuildStepFactory(parent)
{
}

MakeStepFactory::~MakeStepFactory()
{
}

bool MakeStepFactory::canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const
{
    if (parent->target()->project()->id() != QLatin1String(Constants::QT4PROJECT_ID))
        return false;
    return (id == QLatin1String(MAKESTEP_BS_ID));
}

ProjectExplorer::BuildStep *MakeStepFactory::create(ProjectExplorer::BuildStepList *parent, const QString &id)
{
    if (!canCreate(parent, id))
        return 0;
    return new MakeStep(parent);
}

bool MakeStepFactory::canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const
{
    return canCreate(parent, source->id());
}

ProjectExplorer::BuildStep *MakeStepFactory::clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source)
{
    if (!canClone(parent, source))
        return 0;
    return new MakeStep(parent, static_cast<MakeStep *>(source));
}

bool MakeStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const
{
    QString id(ProjectExplorer::idFromMap(map));
    return canCreate(parent, id);
}

ProjectExplorer::BuildStep *MakeStepFactory::restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map)
{
    if (!canRestore(parent, map))
        return 0;
    MakeStep *bs(new MakeStep(parent));
    if (bs->fromMap(map))
        return bs;
    delete bs;
    return 0;
}

QStringList MakeStepFactory::availableCreationIds(ProjectExplorer::BuildStepList *parent) const
{
    if (parent->target()->project()->id() == QLatin1String(Constants::QT4PROJECT_ID))
        return QStringList() << QLatin1String(MAKESTEP_BS_ID);
    return QStringList();
}

QString MakeStepFactory::displayNameForId(const QString &id) const
{
    if (id == QLatin1String(MAKESTEP_BS_ID))
        return tr("Make");
    return QString();
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved.
**
** This file is part of the $MODULE$ of the Qt Toolkit.
**
** $TROLLTECH_DUAL_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "qml.h"
#include "qmlviewer.h"
#include <QWidget>
#include <QDir>
#include <QApplication>
#include <QTranslator>
#include <QDebug>

void usage()
{
    qWarning("Usage: qmlviewer [options] <filename>");
    qWarning(" ");
    qWarning(" options:");
    qWarning("  -v, -version ............................. display version");
    qWarning("  -frameless ............................... run with no window frame");
    qWarning("  -skin <qvfbskindir> ...................... run with a skin window frame");
    qWarning("  -recordfile <output> ..................... set video recording file");
    qWarning("                                              - ImageMagick 'convert' for GIF)");
    qWarning("                                              - png file for raw frames");
    qWarning("                                              - 'ffmpeg' for other formats");
    qWarning("  -recorddither ordered|threshold|floyd .... set GIF dither recording mode");
    qWarning("  -recordperiod <milliseconds> ............. set time between recording frames");
    qWarning("  -record arg .............................. add a recording process argument");
    qWarning("  -autorecord [from-]<tomilliseconds> ...... set recording to start and stop");
    qWarning("  -devicekeys .............................. use numeric keys (see F1)");
    qWarning("  -netcache <size> ......................... set disk cache to size bytes");
    qWarning("  -recordtest <directory> .................. record an autotest");
    qWarning("  -runtest <directory> ..................... run a previously recorded test");
    qWarning("  -translation <translationfile> ........... set the language to run in");
    qWarning("  -L <directory> ........................... prepend to the library search path");
    qWarning(" ");
    qWarning(" Press F1 for interactive help");
    exit(1);
}

int main(int argc, char ** argv)
{
    //### default to using raster graphics backend for now
    bool gsSpecified = false;
    for (int i = 0; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-graphicssystem") {
            gsSpecified = true;
            break;
        }
    }
    if (!gsSpecified)
        QApplication::setGraphicsSystem("raster");

    QApplication app(argc, argv);
    app.setApplicationName("viewer");

    bool frameless = false;
    QString fileName;
    int period = 0;
    int autorecord_from = 0;
    int autorecord_to = 0;
    QString dither = "none";
    QString recordfile;
    QStringList recordargs;
    QStringList libraries;
    QString skin;
    bool devkeys = false;
    int cache = 0;
    QString translationFile;

    for (int i = 1; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-frameless") {
            frameless = true;
        } else if (arg == "-skin") {
            skin = QString(argv[++i]);
        } else if (arg == "-netcache") {
            cache = QString(argv[++i]).toInt();
        } else if (arg == "-recordperiod") {
            period = QString(argv[++i]).toInt();
        } else if (arg == "-recordfile") {
            recordfile = QString(argv[++i]);
        } else if (arg == "-record") {
            recordargs << QString(argv[++i]);
        } else if (arg == "-recorddither") {
            dither = QString(argv[++i]);
        } else if (arg == "-autorecord") {
            QString range = QString(argv[++i]);
            int dash = range.indexOf('-');
            if (dash > 0)
                autorecord_from = range.left(dash).toInt();
            autorecord_to = range.mid(dash+1).toInt();
        } else if (arg == "-devicekeys") {
            devkeys = true;
        } else if (arg == QLatin1String("-v") || arg == QLatin1String("-version")) {
            fprintf(stderr, "Qt Declarative UI Viewer version %s\n", QT_VERSION_STR);
            return 0;
        } else if (arg == "-translation") {
            if(i + 1 >= argc)
                usage();
            translationFile = argv[i + 1];
            ++i;
        } else if (arg == "-L") {
            libraries << QString(argv[++i]);
        } else if (arg[0] != '-') {
            fileName = arg;
        } else if (1 || arg == "-help") {
            usage();
        }
    }

    QTranslator qmlTranslator;
    if (!translationFile.isEmpty()) {
        qmlTranslator.load(translationFile);
        app.installTranslator(&qmlTranslator);
    }

    QmlViewer viewer(0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
    foreach (QString lib, libraries)
        viewer.addLibraryPath(lib);
    viewer.setNetworkCacheSize(cache);
    viewer.setRecordFile(recordfile);
    if (period>0)
        viewer.setRecordPeriod(period);
    if (autorecord_to)
        viewer.setAutoRecord(autorecord_from,autorecord_to);
    if (!skin.isEmpty() && QDir(skin).exists())
        viewer.setSkin(skin);
    if (devkeys)
        viewer.setDeviceKeys(true);
    viewer.setRecordDither(dither);
    viewer.setRecordArgs(recordargs);
    if (!fileName.isEmpty()) {
        viewer.openQml(fileName);
        viewer.show();
    } else {
        viewer.show();
        viewer.open();
    }

    return app.exec();
}
<commit_msg>Update docs (no recordtest/runtest now)<commit_after>/****************************************************************************
**
** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved.
**
** This file is part of the $MODULE$ of the Qt Toolkit.
**
** $TROLLTECH_DUAL_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "qml.h"
#include "qmlviewer.h"
#include <QWidget>
#include <QDir>
#include <QApplication>
#include <QTranslator>
#include <QDebug>

void usage()
{
    qWarning("Usage: qmlviewer [options] <filename>");
    qWarning(" ");
    qWarning(" options:");
    qWarning("  -v, -version ............................. display version");
    qWarning("  -frameless ............................... run with no window frame");
    qWarning("  -skin <qvfbskindir> ...................... run with a skin window frame");
    qWarning("  -recordfile <output> ..................... set video recording file");
    qWarning("                                              - ImageMagick 'convert' for GIF)");
    qWarning("                                              - png file for raw frames");
    qWarning("                                              - 'ffmpeg' for other formats");
    qWarning("  -recorddither ordered|threshold|floyd .... set GIF dither recording mode");
    qWarning("  -recordperiod <milliseconds> ............. set time between recording frames");
    qWarning("  -record arg .............................. add a recording process argument");
    qWarning("  -autorecord [from-]<tomilliseconds> ...... set recording to start and stop");
    qWarning("  -devicekeys .............................. use numeric keys (see F1)");
    qWarning("  -netcache <size> ......................... set disk cache to size bytes");
    qWarning("  -translation <translationfile> ........... set the language to run in");
    qWarning("  -L <directory> ........................... prepend to the library search path");
    qWarning(" ");
    qWarning(" Press F1 for interactive help");
    exit(1);
}

int main(int argc, char ** argv)
{
    //### default to using raster graphics backend for now
    bool gsSpecified = false;
    for (int i = 0; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-graphicssystem") {
            gsSpecified = true;
            break;
        }
    }
    if (!gsSpecified)
        QApplication::setGraphicsSystem("raster");

    QApplication app(argc, argv);
    app.setApplicationName("viewer");

    bool frameless = false;
    QString fileName;
    int period = 0;
    int autorecord_from = 0;
    int autorecord_to = 0;
    QString dither = "none";
    QString recordfile;
    QStringList recordargs;
    QStringList libraries;
    QString skin;
    bool devkeys = false;
    int cache = 0;
    QString translationFile;

    for (int i = 1; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-frameless") {
            frameless = true;
        } else if (arg == "-skin") {
            skin = QString(argv[++i]);
        } else if (arg == "-netcache") {
            cache = QString(argv[++i]).toInt();
        } else if (arg == "-recordperiod") {
            period = QString(argv[++i]).toInt();
        } else if (arg == "-recordfile") {
            recordfile = QString(argv[++i]);
        } else if (arg == "-record") {
            recordargs << QString(argv[++i]);
        } else if (arg == "-recorddither") {
            dither = QString(argv[++i]);
        } else if (arg == "-autorecord") {
            QString range = QString(argv[++i]);
            int dash = range.indexOf('-');
            if (dash > 0)
                autorecord_from = range.left(dash).toInt();
            autorecord_to = range.mid(dash+1).toInt();
        } else if (arg == "-devicekeys") {
            devkeys = true;
        } else if (arg == QLatin1String("-v") || arg == QLatin1String("-version")) {
            fprintf(stderr, "Qt Declarative UI Viewer version %s\n", QT_VERSION_STR);
            return 0;
        } else if (arg == "-translation") {
            if(i + 1 >= argc)
                usage();
            translationFile = argv[i + 1];
            ++i;
        } else if (arg == "-L") {
            libraries << QString(argv[++i]);
        } else if (arg[0] != '-') {
            fileName = arg;
        } else if (1 || arg == "-help") {
            usage();
        }
    }

    QTranslator qmlTranslator;
    if (!translationFile.isEmpty()) {
        qmlTranslator.load(translationFile);
        app.installTranslator(&qmlTranslator);
    }

    QmlViewer viewer(0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
    foreach (QString lib, libraries)
        viewer.addLibraryPath(lib);
    viewer.setNetworkCacheSize(cache);
    viewer.setRecordFile(recordfile);
    if (period>0)
        viewer.setRecordPeriod(period);
    if (autorecord_to)
        viewer.setAutoRecord(autorecord_from,autorecord_to);
    if (!skin.isEmpty() && QDir(skin).exists())
        viewer.setSkin(skin);
    if (devkeys)
        viewer.setDeviceKeys(true);
    viewer.setRecordDither(dither);
    viewer.setRecordArgs(recordargs);
    if (!fileName.isEmpty()) {
        viewer.openQml(fileName);
        viewer.show();
    } else {
        viewer.show();
        viewer.open();
    }

    return app.exec();
}
<|endoftext|>


<commit_before>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include <type_traits>
#include <utility>
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus   >= C++17

namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;

namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class

struct has_iterator_impl
{
    template<typename T> static std::true_type  check(typename T::iterator*);
    template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
    template<typename T> static std::true_type  check(typename T::value_type*);
    template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
    template<typename T> static std::true_type  check(typename T::key_type*);
    template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
    template<typename T> static std::true_type  check(typename T::mapped_type*);
    template<typename T> static std::false_type check(...);
};
struct has_resize_method_impl
{
    constexpr static std::size_t dummy=0;
    template<typename T> static std::true_type  check(decltype(std::declval<T>().resize(dummy))*);
    template<typename T> static std::false_type check(...);
};

struct is_comparable_impl
{
    template<typename T> static std::true_type  check(decltype(std::declval<T>() < std::declval<T>())*);
    template<typename T> static std::false_type check(...);
};

struct has_from_toml_method_impl
{
    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::true_type  check(
        decltype(std::declval<T>().from_toml(
                std::declval<::toml::basic_value<C, Tb, A>>()))*);

    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::false_type check(...);
};
struct has_into_toml_method_impl
{
    template<typename T>
    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
    template<typename T>
    static std::false_type check(...);
};

/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif

template<typename T>
struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};

template<typename T, typename C,
         template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};

template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};

#ifdef __INTEL_COMPILER
#undef decltype
#endif

// ---------------------------------------------------------------------------
// C++17 and/or/not

#if __cplusplus >= 201703L

using std::conjunction;
using std::disjunction;
using std::negation;

#else

template<typename ...> struct conjunction : std::true_type{};
template<typename T>   struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};

template<typename ...> struct disjunction : std::false_type{};
template<typename T>   struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};

template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};

#endif

// ---------------------------------------------------------------------------
// type checkers

template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};

template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};

template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};

template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
    has_iterator<T>,         // has T::iterator
    has_value_type<T>,       // has T::value_type
    has_key_type<T>,         // has T::key_type
    has_mapped_type<T>       // has T::mapped_type
    >{};
template<typename T> struct is_map<T&>                : is_map<T>{};
template<typename T> struct is_map<T const&>          : is_map<T>{};
template<typename T> struct is_map<T volatile&>       : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};

template<typename T>
struct is_container : conjunction<
    negation<is_map<T>>,                         // not a map
    negation<std::is_same<T, std::string>>,      // not a std::string
#if __cplusplus >= 201703L
    negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
    has_iterator<T>,                             // has T::iterator
    has_value_type<T>                            // has T::value_type
    >{};
template<typename T> struct is_container<T&>                : is_container<T>{};
template<typename T> struct is_container<T const&>          : is_container<T>{};
template<typename T> struct is_container<T volatile&>       : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};

template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};

// ---------------------------------------------------------------------------
// C++14 index_sequence

#if __cplusplus >= 201402L

using std::index_sequence;
using std::make_index_sequence;

#else

template<std::size_t ... Ns> struct index_sequence{};

template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
    typedef index_sequence<Ns..., N> type;
};

template<std::size_t N>
struct index_sequence_maker
{
    typedef typename push_back_index_sequence<
        typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
    typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// C++14 enable_if_t

#if __cplusplus >= 201402L

using std::enable_if_t;

#else

template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// return_type_of_t

#if __cplusplus >= 201703L

template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;

#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;

#endif

// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.

template<typename T>
struct is_string_literal:
disjunction<
    std::is_same<const char*, T>,
    conjunction<
        std::is_array<T>,
        std::is_same<const char, typename std::remove_extent<T>::type>
        >
    >{};

// ---------------------------------------------------------------------------
// C++20 remove_cvref_t

template<typename T>
struct remove_cvref
{
    using type = typename std::remove_cv<
        typename std::remove_reference<T>::type>::type;
};

template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

}// detail
}//toml
#endif // TOML_TRAITS
<commit_msg>feat: add meta funcs, has_reserve/push_back_method<commit_after>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include <type_traits>
#include <utility>
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus   >= C++17

namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;

namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class

struct has_iterator_impl
{
    template<typename T> static std::true_type  check(typename T::iterator*);
    template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
    template<typename T> static std::true_type  check(typename T::value_type*);
    template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
    template<typename T> static std::true_type  check(typename T::key_type*);
    template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
    template<typename T> static std::true_type  check(typename T::mapped_type*);
    template<typename T> static std::false_type check(...);
};
struct has_reserve_method_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>() < std::declval<T>())*);
};

struct has_from_toml_method_impl
{
    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::true_type  check(
        decltype(std::declval<T>().from_toml(
                std::declval<::toml::basic_value<C, Tb, A>>()))*);

    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::false_type check(...);
};
struct has_into_toml_method_impl
{
    template<typename T>
    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
    template<typename T>
    static std::false_type check(...);
};

/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif

template<typename T>
struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};

template<typename T, typename C,
         template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};

template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};

#ifdef __INTEL_COMPILER
#undef decltype
#endif

// ---------------------------------------------------------------------------
// C++17 and/or/not

#if __cplusplus >= 201703L

using std::conjunction;
using std::disjunction;
using std::negation;

#else

template<typename ...> struct conjunction : std::true_type{};
template<typename T>   struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};

template<typename ...> struct disjunction : std::false_type{};
template<typename T>   struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};

template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};

#endif

// ---------------------------------------------------------------------------
// type checkers

template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};

template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};

template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};

template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
    has_iterator<T>,         // has T::iterator
    has_value_type<T>,       // has T::value_type
    has_key_type<T>,         // has T::key_type
    has_mapped_type<T>       // has T::mapped_type
    >{};
template<typename T> struct is_map<T&>                : is_map<T>{};
template<typename T> struct is_map<T const&>          : is_map<T>{};
template<typename T> struct is_map<T volatile&>       : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};

template<typename T>
struct is_container : conjunction<
    negation<is_map<T>>,                         // not a map
    negation<std::is_same<T, std::string>>,      // not a std::string
#if __cplusplus >= 201703L
    negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
    has_iterator<T>,                             // has T::iterator
    has_value_type<T>                            // has T::value_type
    >{};
template<typename T> struct is_container<T&>                : is_container<T>{};
template<typename T> struct is_container<T const&>          : is_container<T>{};
template<typename T> struct is_container<T volatile&>       : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};

template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};

// ---------------------------------------------------------------------------
// C++14 index_sequence

#if __cplusplus >= 201402L

using std::index_sequence;
using std::make_index_sequence;

#else

template<std::size_t ... Ns> struct index_sequence{};

template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
    typedef index_sequence<Ns..., N> type;
};

template<std::size_t N>
struct index_sequence_maker
{
    typedef typename push_back_index_sequence<
        typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
    typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// C++14 enable_if_t

#if __cplusplus >= 201402L

using std::enable_if_t;

#else

template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// return_type_of_t

#if __cplusplus >= 201703L

template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;

#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;

#endif

// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.

template<typename T>
struct is_string_literal:
disjunction<
    std::is_same<const char*, T>,
    conjunction<
        std::is_array<T>,
        std::is_same<const char, typename std::remove_extent<T>::type>
        >
    >{};

// ---------------------------------------------------------------------------
// C++20 remove_cvref_t

template<typename T>
struct remove_cvref
{
    using type = typename std::remove_cv<
        typename std::remove_reference<T>::type>::type;
};

template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

}// detail
}//toml
#endif // TOML_TRAITS
<|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#ifndef MFEM_LINEARFORM
#define MFEM_LINEARFORM

#include "../config/config.hpp"
#include "lininteg.hpp"
#include "gridfunc.hpp"

namespace mfem
{

/// Class for linear form - Vector with associated FE space and LFIntegrators.
class LinearForm : public Vector
{
private:
   /// FE space on which LF lives.
   FiniteElementSpace * fes;

   /// Set of Domain Integrators to be applied.
   Array<LinearFormIntegrator*> dlfi;

   /// Separate array for integrators with delta function coefficients.
   Array<DeltaLFIntegrator*> dlfi_delta;

   /// Set of Boundary Integrators to be applied.
   Array<LinearFormIntegrator*> blfi;

   /// Set of Boundary Face Integrators to be applied.
   Array<LinearFormIntegrator*> flfi;
   Array<Array<int>*>           flfi_marker;

   /// The element ids where the centers of the delta functions lie
   Array<int> dlfi_delta_elem_id;

   /// The reference coordinates where the centers of the delta functions lie
   Array<IntegrationPoint> dlfi_delta_ip;

   /// If true, the delta locations are not (re)computed during assembly.
   bool HaveDeltaLocations() { return (dlfi_delta_elem_id.Size() != 0); }

   /// Force (re)computation of delta locations.
   void ResetDeltaLocations() { dlfi_delta_elem_id.SetSize(0); }

public:
   /// Creates linear form associated with FE space *f.
   LinearForm (FiniteElementSpace * f) : Vector (f -> GetVSize())
   { fes = f; }

   LinearForm() { fes = NULL; }

   /// (DEPRECATED) Return the FE space associated with the LinearForm.
   /** @deprecated Use FESpace() instead. */
   FiniteElementSpace * GetFES() { return fes; }

   /// Read+write access to the associated FiniteElementSpace.
   FiniteElementSpace *FESpace() { return fes; }
   /// Read-only access to the associated FiniteElementSpace.
   const FiniteElementSpace *FESpace() const { return fes; }

   /// Adds new Domain Integrator.
   void AddDomainIntegrator (LinearFormIntegrator * lfi);

   /// Adds new Boundary Integrator.
   void AddBoundaryIntegrator (LinearFormIntegrator * lfi);

   /// Adds new Boundary Face Integrator.
   void AddBdrFaceIntegrator (LinearFormIntegrator * lfi);

   /** @brief Add new Boundary Face Integrator, restricted to the given boundary
       attributes. */
   void AddBdrFaceIntegrator(LinearFormIntegrator *lfi,
                             Array<int> &bdr_attr_marker);

   /// Assembles the linear form i.e. sums over all domain/bdr integrators.
   void Assemble();

   /// Assembles delta functions of the linear form
   void AssembleDelta();

   void Update() { SetSize(fes->GetVSize()); ResetDeltaLocations(); }

   void Update(FiniteElementSpace *f)
   { fes = f; SetSize(f->GetVSize()); ResetDeltaLocations(); }

   void Update(FiniteElementSpace *f, Vector &v, int v_offset);

   /// Return the action of the LinearForm as a linear mapping.
   /** Linear forms are linear functionals which map GridFunctions to
       the real numbers.  This method performs this mapping which in
       this case is equivalent as an inner product of the LinearForm
       and GridFunction. */
   double operator()(const GridFunction &gf) const { return (*this)*gf; }

   /// Destroys linear form.
   ~LinearForm();
};

}

#endif
<commit_msg>Adding LinearForm constructor which takes a data array<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#ifndef MFEM_LINEARFORM
#define MFEM_LINEARFORM

#include "../config/config.hpp"
#include "lininteg.hpp"
#include "gridfunc.hpp"

namespace mfem
{

/// Class for linear form - Vector with associated FE space and LFIntegrators.
class LinearForm : public Vector
{
private:
   /// FE space on which LF lives.
   FiniteElementSpace * fes;

   /// Set of Domain Integrators to be applied.
   Array<LinearFormIntegrator*> dlfi;

   /// Separate array for integrators with delta function coefficients.
   Array<DeltaLFIntegrator*> dlfi_delta;

   /// Set of Boundary Integrators to be applied.
   Array<LinearFormIntegrator*> blfi;

   /// Set of Boundary Face Integrators to be applied.
   Array<LinearFormIntegrator*> flfi;
   Array<Array<int>*>           flfi_marker;

   /// The element ids where the centers of the delta functions lie
   Array<int> dlfi_delta_elem_id;

   /// The reference coordinates where the centers of the delta functions lie
   Array<IntegrationPoint> dlfi_delta_ip;

   /// If true, the delta locations are not (re)computed during assembly.
   bool HaveDeltaLocations() { return (dlfi_delta_elem_id.Size() != 0); }

   /// Force (re)computation of delta locations.
   void ResetDeltaLocations() { dlfi_delta_elem_id.SetSize(0); }

public:
   /// Creates linear form associated with FE space *f.
   LinearForm (FiniteElementSpace * f) : Vector (f -> GetVSize())
   { fes = f; }

   /// Construct a GridFunction using previously allocated array @a data.
   /** The GridFunction does not assume ownership of @a data which is assumed to
       be of size at least `f->GetVSize()`. Similar to the Vector constructor
       for externally allocated array, the pointer @a data can be NULL. The data
       array can be replaced later using the method SetData().
    */
   LinearForm(FiniteElementSpace *f, double *data) : Vector(data, f->GetVSize())
   { fes = f; }

   LinearForm() { fes = NULL; }

   /// (DEPRECATED) Return the FE space associated with the LinearForm.
   /** @deprecated Use FESpace() instead. */
   FiniteElementSpace * GetFES() { return fes; }

   /// Read+write access to the associated FiniteElementSpace.
   FiniteElementSpace *FESpace() { return fes; }
   /// Read-only access to the associated FiniteElementSpace.
   const FiniteElementSpace *FESpace() const { return fes; }

   /// Adds new Domain Integrator.
   void AddDomainIntegrator (LinearFormIntegrator * lfi);

   /// Adds new Boundary Integrator.
   void AddBoundaryIntegrator (LinearFormIntegrator * lfi);

   /// Adds new Boundary Face Integrator.
   void AddBdrFaceIntegrator (LinearFormIntegrator * lfi);

   /** @brief Add new Boundary Face Integrator, restricted to the given boundary
       attributes. */
   void AddBdrFaceIntegrator(LinearFormIntegrator *lfi,
                             Array<int> &bdr_attr_marker);

   /// Assembles the linear form i.e. sums over all domain/bdr integrators.
   void Assemble();

   /// Assembles delta functions of the linear form
   void AssembleDelta();

   void Update() { SetSize(fes->GetVSize()); ResetDeltaLocations(); }

   void Update(FiniteElementSpace *f)
   { fes = f; SetSize(f->GetVSize()); ResetDeltaLocations(); }

   void Update(FiniteElementSpace *f, Vector &v, int v_offset);

   /// Return the action of the LinearForm as a linear mapping.
   /** Linear forms are linear functionals which map GridFunctions to
       the real numbers.  This method performs this mapping which in
       this case is equivalent as an inner product of the LinearForm
       and GridFunction. */
   double operator()(const GridFunction &gf) const { return (*this)*gf; }

   /// Destroys linear form.
   ~LinearForm();
};

}

#endif
<|endoftext|>


<commit_before>#include "PID.h"

/**
 * A PID Controller is a method of system control in which a correctional output
 * is generated to guide the system toward a desired setpoint (aka target).
 * The PID Controller calculates the output based on the following factors:
 *
 *    Gains (proportional, integral, and derivative)
 *    Target
 *    Feedback
 *
 * The gain values act as multipliers for their corresponding components of PID
 * (more detail later).  The target is the value which the system strives to
 * reach by manipulating the output.  The feedback is the system's actual
 * position or status in regards to the physical world.
 * Another important term in PID is "error", which refers to the difference
 * between the target and the feedback.
 *
 * Each of the three components of PID contributes a unique behavior to the
 * system.
 *
 *    The Proportional component introduces a linear relationship between the
 *    error (target minus feedback) and the output.  This means that as the
 *    feedback grows further away from the target, the output grows
 *    proportionally stronger.
 *
 *        Proportional component = (P Gain) * (target - feedback)
 *
 *    The Integral component is designed to give a very precise approach of the
 *    feedback to the target.  Depending on the scale of the physical system
 *    and the precision of feedback (e.g. sensors), the proportional component
 *    alone is likely not sufficient to provide adequate power (e.g. to motors)
 *    to guide the system in regards to small-scale correction.  The Integral
 *    component integrates the error of the system (target - feedback) over
 *    time.  If the system reaches a point where it is close but not exactly
 *    on top of the target, the integration will slowly build until it is
 *    powerful enough to overcome static resistances and move the system
 *    preciesly to the target.
 *
 *        Integral component = (I Gain) * Integral of error over time
 *
 *          *In this implementation, Integral is calculated with a running
 *          summation of the system's error, updated at each tick.
 *
 *    The Derivative component measures the rate of change of the feedback.
 *    It can reduce the strength of the output if the feedback is approaching
 *    the target too quickly or if the feedback is moving away from the target.
 *
 *        Derivative component = (D Gain) * ((error - lastError) / time - lastTime)
 *
 * The output generated by the PID Controller is the sum of the three
 * components.
 *
 *    PID output = Proportional component + Integral component + Derivative component
 */
PIDController::PIDController(double p, double i, double d, int (*pidSource)(), void (*pidOutput)(int output))
{
  _p = p;
  _i = i;
  _d = d;
  target = 0;
  output = 0;
  currentFeedback = 0;
  lastFeedback = 0;
  lastError = 0;
  currentTime = 0L;
  lastTime = 0L;
  integralCumulation = 0;
  maxCumulation = 30000;
  inputBounded = false;
  outputBounded = false;
  inputLowerBound = 0;
  inputUpperBound = 0;
  outputBounded = false;
  outputLowerBound = 0;
  outputUpperBound = 0;
  timeFunctionRegistered = false;
  _pidSource = pidSource;
  _pidOutput = pidOutput;
}

/**
 * This method uses the established function pointers to retrieve system
 * feedback, calculate the PID output, and deliver the correction value
 * to the parent of this PIDController.  This method should be run as
 * fast as the source of the feedback in order to provide the highest
 * resolution of control (for example, to be placed in the loop() method).
 */
void PIDController::tick()
{
  //Retrieve system feedback from user callback.
  currentFeedback = _pidSource();

  //Apply input bounds if necessary.
  if(inputBounded)
  {
    if(currentFeedback > inputUpperBound) currentFeedback = inputUpperBound;
    if(currentFeedback < inputLowerBound) currentFeedback = inputLowerBound;
  }

  //Calculate the error between the feedback and the target.
  error = target - currentFeedback;

  //If we have a registered way to retrieve the system time, use time in PID calculations.
  if(timeFunctionRegistered)
  {
    //Retrieve system time
    currentTime = _getSystemTime();

    //Calculate time since last tick() cycle.
    long deltaTime = currentTime - lastTime;

    //Calculate the integral of the feedback data since last cycle.
    int cycleIntegral = (lastError + error / 2) * deltaTime;

    //Add this cycle's integral to the integral cumulation.
    integralCumulation += cycleIntegral;

    //Calculate the slope of the line with data from the current and last cycles.
    cycleDerivative = (error - lastError) / deltaTime;

    //Save time data for next iteration.
    lastTime = currentTime;
  }
  //If we have no way to retrieve system time, estimate calculations.
  else
  {
    integralCumulation += error;
    cycleDerivative = (error - lastError);
  }

  //Prevent the integral cumulation from becoming overwhelmingly huge.
  if(integralCumulation > maxCumulation) integralCumulation = maxCumulation;
  if(integralCumulation < -maxCumulation) integralCumulation = -maxCumulation;

  //Calculate the system output based on data and PID gains.
  output = (int) ((error * _p) + (integralCumulation * _i) + (cycleDerivative * _d));

  //Save a record of this iteration's data.
  lastFeedback = currentFeedback;
  lastError = error;

  //Trim the output to the bounds if needed.
  if(outputBounded)
  {
    if(output > outputUpperBound) output = outputUpperBound;
    if(output < outputLowerBound) output = outputLowerBound;
  }

  _pidOutput(output);
}

/**
 * Sets the target of this PIDController.  This system will generate
 * correction outputs indended to guide the feedback variable (such
 * as position, velocity, etc.) toward the established target.
 */
void PIDController::setTarget(int t)
{
  target = t;
}

/**
 * Returns the current target of this PIDController.
 * @return The current target of this PIDController.
 */
int PIDController::getTarget()
{
  return target;
}

/**
 * Returns the latest output generated by this PIDController.  This value is
 * also delivered to the parent systems via the PIDOutput function pointer
 * provided in the constructor of this PIDController.
 * @return The latest output generated by this PIDController.
 */
int PIDController::getOutput()
{
  return output;
}

/**
 * Returns the last read feedback of this PIDController.
 */
int PIDController::getFeedback()
{
  return currentFeedback;
}

/**
 * Returns the value that the Proportional component is contributing to the output.
 * @return The value that the Proportional component is contributing to the output.
 */
int PIDController::getProportionalComponent()
{
  return (int) (error * _p);
}

/**
 * Returns the value that the Integral component is contributing to the output.
 * @return The value that the Integral component is contributing to the output.
 */
int PIDController::getIntegralComponent()
{
  return (int) (integralCumulation * _i);
}

/**
 * Returns the value that the Derivative component is contributing to the output.
 * @return The value that the Derivative component is contributing to the output.
 */
int PIDController::getDerivativeComponent()
{
  return (int) (cycleDerivative * _d);
}

/**
 * Sets the maximum value that the integral cumulation can reach.
 * @param max The maximum value of the integral cumulation.
 */
void PIDController::setMaxIntegralCumulation(int max)
{
  //If the new max value is less than 0, invert to make positive.
  if(max < 0)
  {
    max = -max;
  }

  //If the new max is not more than 1 then the cumulation is useless.
  if(max > 1)
  {
    maxCumulation = max;
  }
}

/**
 * Returns the maximum value that the integral value can cumulate to.
 * @return The maximum value that the integral value can cumulate to.
 */
int PIDController::getMaxIntegralCumulation()
{
  return maxCumulation;
}

/**
 * Returns the current cumulative integral value in this PIDController.
 * @return The current cumulative integral value in this PIDController.
 */
int PIDController::getIntegralCumulation()
{
  return integralCumulation;
}

/**
 * Enables or disables bounds on the input.  Bounds limit the upper and
 * lower values that this PIDController will ever accept as input.
 * Outlying values will be trimmed to the upper or lower bound as necessary.
 * @param bounded True to enable input bounds, False to disable.
 */
void PIDController::setInputBounded(bool bounded)
{
  inputBounded = bounded;
}

/**
 * Enables or disables bounds on the output.  Bounds limit the upper and lower
 * values that this PIDController will ever generate as output.
 * @param bounded True to enable output bounds, False to disable.
 */
void PIDController::setOutputBounded(bool bounded)
{
  outputBounded = bounded;
}

/**
 * Returns whether the input of this PIDController is being bounded.
 * @return True if the input of this PIDController is being bounded.
 */
bool PIDController::isInputBounded()
{
  return inputBounded;
}

/**
 * Returns whether the output of this PIDController is being bounded.
 * @return True if the output of this PIDController is being bounded.
 */
bool PIDController::isOutputBounded()
{
  return outputBounded;
}

/**
 * Sets bounds which limit the lower and upper extremes that this PIDController
 * accepts as inputs.  Outliers are trimmed to the lower and upper bounds.
 * Setting input bounds automatically enables input bounds.
 * @param lower The lower input bound.
 * @param upper The upper input bound.
 */
void PIDController::setInputBounds(int lower, int upper)
{
  if(upper > lower)
  {
    inputBounded = true;
    inputUpperBound = upper;
    inputLowerBound = lower;
  }
}

/**
 * Sets bounds which limit the lower and upper extremes that this PIDController
 * will ever generate as output.  Setting output bounds automatically enables
 * output bounds.
 * @param lower The lower output bound.
 * @param upper The upper output bound.
 */
void PIDController::setOutputBounds(int lower, int upper)
{
  if(upper > lower)
  {
    outputBounded = true;
    outputLowerBound = lower;
    outputUpperBound = upper;
  }
}

/**
 * Returns the lower input bound of this PIDController.
 * @return The lower input bound of this PIDController.
 */
int PIDController::getInputLowerBound()
{
  return inputLowerBound;
}

/**
 * Returns the upper input bound of this PIDController.
 * @return The upper input bound of this PIDController.
 */
int PIDController::getInputUpperBound()
{
  return inputUpperBound;
}

/**
 * Returns the lower output bound of this PIDController.
 * @return The lower output bound of this PIDController.
 */
int PIDController::getOutputLowerBound()
{
  return outputLowerBound;
}

/**
 * Returns the upper output bound of this PIDController.
 * @return The upper output bound of this PIDController.
 */
int PIDController::getOutputUpperBound()
{
  return outputUpperBound;
}

/**
 * Sets new values for all PID Gains.
 * @param p The new proportional gain.
 * @param i The new integral gain.
 * @param d The new derivative gain.
 */
void PIDController::setPID(double p, double i, double d)
{
  _p = p;
  _i = i;
  _d = d;
}

/**
 * Sets a new value for the proportional gain.
 * @param p The new proportional gain.
 */
void PIDController::setP(double p)
{
  _p = p;
}

/**
 * Sets a new value for the integral gain.
 * @param i The new integral gain.
 */
void PIDController::setI(double i)
{
  _i = i;
}

/**
 * Sets a new value for the derivative gain.
 * @param d The new derivative gain.
 */
void PIDController::setD(double d)
{
  _d = d;
}

/**
 * Returns the proportional gain.
 * @return The proportional gain.
 */
double PIDController::getP()
{
  return _p;
}

/**
 * Returns the integral gain.
 * @return The integral gain.
 */
double PIDController::getI()
{
  return _i;
}

/**
 * Returns the derivative gain.
 * @return The derivative gain.
 */
double PIDController::getD()
{
  return _d;
}

/**
 * Sets the function pointer to the PID Source.  A PID Source
 * is a function which returns a value to be used as the PIDController's
 * control feedback.  This value can be a reading from a sensor or other
 * data source that contains information regarding the system's actual
 * state.
 * Below is an example of using a PIDSource:
 *
 *    int pidSource()
 *    {
 *        return mySensor.getValue();
 *    }
 *    myPIDController.setPIDSource(pidSource);
 *
 * @param (*getFeedback) A function pointer that retrieves system feedback.
 */
void PIDController::setPIDSource(int (*pidSource)())
{
  _pidSource = pidSource;
}

/**
 * Sets the function pointer to the PID Output.  A PID Output
 * is a function which delivers a value to the parent system in order to guide
 * the system based on the PID loop's result.  This value can be delivered
 * directly to motors, to a variable that directs steering, or other means of
 * influencing the system.
 * Below is an example of using a PIDOutput:
 *
 *    void pidOutput(int output)
 *    {
 *        myMotor.write(output);
 *    }
 *    myPIDController.setPIDOutput(pidOutput);
 *
 * @param (*onUpdate) A function pointer that delivers system output.
 */
void PIDController::setPIDOutput(void (*pidOutput)(int output))
{
  _pidOutput = pidOutput;
}

/**
 * Use this to add a hook into the PID Controller that allows it to
 * read the system time no matter what platform this library is run
 * on.  Though developed for an arduino project, there is no code
 * tying this library to the arduino project.  To use the arduino
 * clock, however, register the time-getting function (millis())
 * like this:
 *
 *    myPIDController.registerTimeInput(millis);
 *    *Note that in this example, millis has no parentheses.
 *
 * @param (*getSystemTime) Pointer to a function that returns system time.
 */
void PIDController::registerTimeFunction(unsigned long (*getSystemTime)())
{
  _getSystemTime = getSystemTime;
  timeFunctionRegistered = true;
}
<commit_msg>Added author and moved intro doc above include<commit_after>/**
 * @author Nick Mosher, <codewhisperer97@gmail.com>
 *
 * A PID Controller is a method of system control in which a correctional output
 * is generated to guide the system toward a desired setpoint (aka target).
 * The PID Controller calculates the output based on the following factors:
 *
 *    Gains (proportional, integral, and derivative)
 *    Target
 *    Feedback
 *
 * The gain values act as multipliers for their corresponding components of PID
 * (more detail later).  The target is the value which the system strives to
 * reach by manipulating the output.  The feedback is the system's actual
 * position or status in regards to the physical world.
 * Another important term in PID is "error", which refers to the difference
 * between the target and the feedback.
 *
 * Each of the three components of PID contributes a unique behavior to the
 * system.
 *
 *    The Proportional component introduces a linear relationship between the
 *    error (target minus feedback) and the output.  This means that as the
 *    feedback grows further away from the target, the output grows
 *    proportionally stronger.
 *
 *        Proportional component = (P Gain) * (target - feedback)
 *
 *    The Integral component is designed to give a very precise approach of the
 *    feedback to the target.  Depending on the scale of the physical system
 *    and the precision of feedback (e.g. sensors), the proportional component
 *    alone is likely not sufficient to provide adequate power (e.g. to motors)
 *    to guide the system in regards to small-scale corrections.  The Integral
 *    component integrates the error of the system (target - feedback) over
 *    time.  If the system reaches a point where it is close but not exactly
 *    on top of the target, the integration will slowly build until it is
 *    powerful enough to overcome static resistances and move the system
 *    preciesly to the target.
 *
 *        Integral component = (I Gain) * Integral of error over time
 *
 *          *In this implementation, Integral is calculated with a running
 *          summation of the system's error, updated at each tick.
 *
 *    The Derivative component measures the rate of change of the feedback.
 *    It can reduce the strength of the output if the feedback is approaching
 *    the target too quickly or if the feedback is moving away from the target.
 *
 *        Derivative component = (D Gain) * ((error - lastError) / time - lastTime)
 *
 * The output generated by the PID Controller is the sum of the three
 * components.
 *
 *    PID output = Proportional component + Integral component + Derivative component
 */

#include "PID.h"

/**
 * Constructs the PIDController object with PID Gains and function pointers
 * for retrieving feedback (pidSource) and delivering output (pidOutput).
 * All PID gains should be positive, otherwise the system will violently diverge
 * from the target.
 * @param p The Proportional gain.
 * @param i The Integral gain.
 * @param d The Derivative gain.
 * @param (*pidSource) The function pointer for retrieving system feedback.
 * @param (*pidOutput) The function pointer for delivering system output.
 */
PIDController::PIDController(double p, double i, double d, int (*pidSource)(), void (*pidOutput)(int output))
{
  _p = p;
  _i = i;
  _d = d;
  target = 0;
  output = 0;
  currentFeedback = 0;
  lastFeedback = 0;
  lastError = 0;
  currentTime = 0L;
  lastTime = 0L;
  integralCumulation = 0;
  maxCumulation = 30000;
  inputBounded = false;
  outputBounded = false;
  inputLowerBound = 0;
  inputUpperBound = 0;
  outputBounded = false;
  outputLowerBound = 0;
  outputUpperBound = 0;
  timeFunctionRegistered = false;
  _pidSource = pidSource;
  _pidOutput = pidOutput;
}

/**
 * This method uses the established function pointers to retrieve system
 * feedback, calculate the PID output, and deliver the correction value
 * to the parent of this PIDController.  This method should be run as
 * fast as the source of the feedback in order to provide the highest
 * resolution of control (for example, to be placed in the loop() method).
 */
void PIDController::tick()
{
  //Retrieve system feedback from user callback.
  currentFeedback = _pidSource();

  //Apply input bounds if necessary.
  if(inputBounded)
  {
    if(currentFeedback > inputUpperBound) currentFeedback = inputUpperBound;
    if(currentFeedback < inputLowerBound) currentFeedback = inputLowerBound;
  }

  //Calculate the error between the feedback and the target.
  error = target - currentFeedback;

  //If we have a registered way to retrieve the system time, use time in PID calculations.
  if(timeFunctionRegistered)
  {
    //Retrieve system time
    currentTime = _getSystemTime();

    //Calculate time since last tick() cycle.
    long deltaTime = currentTime - lastTime;

    //Calculate the integral of the feedback data since last cycle.
    int cycleIntegral = (lastError + error / 2) * deltaTime;

    //Add this cycle's integral to the integral cumulation.
    integralCumulation += cycleIntegral;

    //Calculate the slope of the line with data from the current and last cycles.
    cycleDerivative = (error - lastError) / deltaTime;

    //Save time data for next iteration.
    lastTime = currentTime;
  }
  //If we have no way to retrieve system time, estimate calculations.
  else
  {
    integralCumulation += error;
    cycleDerivative = (error - lastError);
  }

  //Prevent the integral cumulation from becoming overwhelmingly huge.
  if(integralCumulation > maxCumulation) integralCumulation = maxCumulation;
  if(integralCumulation < -maxCumulation) integralCumulation = -maxCumulation;

  //Calculate the system output based on data and PID gains.
  output = (int) ((error * _p) + (integralCumulation * _i) + (cycleDerivative * _d));

  //Save a record of this iteration's data.
  lastFeedback = currentFeedback;
  lastError = error;

  //Trim the output to the bounds if needed.
  if(outputBounded)
  {
    if(output > outputUpperBound) output = outputUpperBound;
    if(output < outputLowerBound) output = outputLowerBound;
  }

  _pidOutput(output);
}

/**
 * Sets the target of this PIDController.  This system will generate
 * correction outputs indended to guide the feedback variable (such
 * as position, velocity, etc.) toward the established target.
 */
void PIDController::setTarget(int t)
{
  target = t;
}

/**
 * Returns the current target of this PIDController.
 * @return The current target of this PIDController.
 */
int PIDController::getTarget()
{
  return target;
}

/**
 * Returns the latest output generated by this PIDController.  This value is
 * also delivered to the parent systems via the PIDOutput function pointer
 * provided in the constructor of this PIDController.
 * @return The latest output generated by this PIDController.
 */
int PIDController::getOutput()
{
  return output;
}

/**
 * Returns the last read feedback of this PIDController.
 */
int PIDController::getFeedback()
{
  return currentFeedback;
}

/**
 * Returns the value that the Proportional component is contributing to the output.
 * @return The value that the Proportional component is contributing to the output.
 */
int PIDController::getProportionalComponent()
{
  return (int) (error * _p);
}

/**
 * Returns the value that the Integral component is contributing to the output.
 * @return The value that the Integral component is contributing to the output.
 */
int PIDController::getIntegralComponent()
{
  return (int) (integralCumulation * _i);
}

/**
 * Returns the value that the Derivative component is contributing to the output.
 * @return The value that the Derivative component is contributing to the output.
 */
int PIDController::getDerivativeComponent()
{
  return (int) (cycleDerivative * _d);
}

/**
 * Sets the maximum value that the integral cumulation can reach.
 * @param max The maximum value of the integral cumulation.
 */
void PIDController::setMaxIntegralCumulation(int max)
{
  //If the new max value is less than 0, invert to make positive.
  if(max < 0)
  {
    max = -max;
  }

  //If the new max is not more than 1 then the cumulation is useless.
  if(max > 1)
  {
    maxCumulation = max;
  }
}

/**
 * Returns the maximum value that the integral value can cumulate to.
 * @return The maximum value that the integral value can cumulate to.
 */
int PIDController::getMaxIntegralCumulation()
{
  return maxCumulation;
}

/**
 * Returns the current cumulative integral value in this PIDController.
 * @return The current cumulative integral value in this PIDController.
 */
int PIDController::getIntegralCumulation()
{
  return integralCumulation;
}

/**
 * Enables or disables bounds on the input.  Bounds limit the upper and
 * lower values that this PIDController will ever accept as input.
 * Outlying values will be trimmed to the upper or lower bound as necessary.
 * @param bounded True to enable input bounds, False to disable.
 */
void PIDController::setInputBounded(bool bounded)
{
  inputBounded = bounded;
}

/**
 * Enables or disables bounds on the output.  Bounds limit the upper and lower
 * values that this PIDController will ever generate as output.
 * @param bounded True to enable output bounds, False to disable.
 */
void PIDController::setOutputBounded(bool bounded)
{
  outputBounded = bounded;
}

/**
 * Returns whether the input of this PIDController is being bounded.
 * @return True if the input of this PIDController is being bounded.
 */
bool PIDController::isInputBounded()
{
  return inputBounded;
}

/**
 * Returns whether the output of this PIDController is being bounded.
 * @return True if the output of this PIDController is being bounded.
 */
bool PIDController::isOutputBounded()
{
  return outputBounded;
}

/**
 * Sets bounds which limit the lower and upper extremes that this PIDController
 * accepts as inputs.  Outliers are trimmed to the lower and upper bounds.
 * Setting input bounds automatically enables input bounds.
 * @param lower The lower input bound.
 * @param upper The upper input bound.
 */
void PIDController::setInputBounds(int lower, int upper)
{
  if(upper > lower)
  {
    inputBounded = true;
    inputUpperBound = upper;
    inputLowerBound = lower;
  }
}

/**
 * Sets bounds which limit the lower and upper extremes that this PIDController
 * will ever generate as output.  Setting output bounds automatically enables
 * output bounds.
 * @param lower The lower output bound.
 * @param upper The upper output bound.
 */
void PIDController::setOutputBounds(int lower, int upper)
{
  if(upper > lower)
  {
    outputBounded = true;
    outputLowerBound = lower;
    outputUpperBound = upper;
  }
}

/**
 * Returns the lower input bound of this PIDController.
 * @return The lower input bound of this PIDController.
 */
int PIDController::getInputLowerBound()
{
  return inputLowerBound;
}

/**
 * Returns the upper input bound of this PIDController.
 * @return The upper input bound of this PIDController.
 */
int PIDController::getInputUpperBound()
{
  return inputUpperBound;
}

/**
 * Returns the lower output bound of this PIDController.
 * @return The lower output bound of this PIDController.
 */
int PIDController::getOutputLowerBound()
{
  return outputLowerBound;
}

/**
 * Returns the upper output bound of this PIDController.
 * @return The upper output bound of this PIDController.
 */
int PIDController::getOutputUpperBound()
{
  return outputUpperBound;
}

/**
 * Sets new values for all PID Gains.
 * @param p The new proportional gain.
 * @param i The new integral gain.
 * @param d The new derivative gain.
 */
void PIDController::setPID(double p, double i, double d)
{
  _p = p;
  _i = i;
  _d = d;
}

/**
 * Sets a new value for the proportional gain.
 * @param p The new proportional gain.
 */
void PIDController::setP(double p)
{
  _p = p;
}

/**
 * Sets a new value for the integral gain.
 * @param i The new integral gain.
 */
void PIDController::setI(double i)
{
  _i = i;
}

/**
 * Sets a new value for the derivative gain.
 * @param d The new derivative gain.
 */
void PIDController::setD(double d)
{
  _d = d;
}

/**
 * Returns the proportional gain.
 * @return The proportional gain.
 */
double PIDController::getP()
{
  return _p;
}

/**
 * Returns the integral gain.
 * @return The integral gain.
 */
double PIDController::getI()
{
  return _i;
}

/**
 * Returns the derivative gain.
 * @return The derivative gain.
 */
double PIDController::getD()
{
  return _d;
}

/**
 * Sets the function pointer to the PID Source.  A PID Source
 * is a function which returns a value to be used as the PIDController's
 * control feedback.  This value can be a reading from a sensor or other
 * data source that contains information regarding the system's actual
 * state.
 * Below is an example of using a PIDSource:
 *
 *    int pidSource()
 *    {
 *        return mySensor.getValue();
 *    }
 *    myPIDController.setPIDSource(pidSource);
 *
 * @param (*getFeedback) A function pointer that retrieves system feedback.
 */
void PIDController::setPIDSource(int (*pidSource)())
{
  _pidSource = pidSource;
}

/**
 * Sets the function pointer to the PID Output.  A PID Output
 * is a function which delivers a value to the parent system in order to guide
 * the system based on the PID loop's result.  This value can be delivered
 * directly to motors, to a variable that directs steering, or other means of
 * influencing the system.
 * Below is an example of using a PIDOutput:
 *
 *    void pidOutput(int output)
 *    {
 *        myMotor.write(output);
 *    }
 *    myPIDController.setPIDOutput(pidOutput);
 *
 * @param (*onUpdate) A function pointer that delivers system output.
 */
void PIDController::setPIDOutput(void (*pidOutput)(int output))
{
  _pidOutput = pidOutput;
}

/**
 * Use this to add a hook into the PID Controller that allows it to
 * read the system time no matter what platform this library is run
 * on.  Though developed for an arduino project, there is no code
 * tying this library to the arduino project.  To use the arduino
 * clock, however, register the time-getting function (millis())
 * like this:
 *
 *    myPIDController.registerTimeInput(millis);
 *    *Note that in this example, millis has no parentheses.
 *
 * @param (*getSystemTime) Pointer to a function that returns system time.
 */
void PIDController::registerTimeFunction(unsigned long (*getSystemTime)())
{
  _getSystemTime = getSystemTime;
  timeFunctionRegistered = true;
}
<|endoftext|>