<commit_before>#include "arc_factored.h"

#include <vector>
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/program_options/variables_map.hpp>

#include "arc_ff.h"
#include "stringlib.h"
#include "filelib.h"
#include "tdict.h"
#include "dep_training.h"
#include "optimize.h"
#include "weights.h"

using namespace std;
namespace po = boost::program_options;

void InitCommandLine(int argc, char** argv, po::variables_map* conf) {
  po::options_description opts("Configuration options");
  string cfg_file;
  opts.add_options()
        ("training_data,t",po::value<string>()->default_value("-"), "File containing training data (jsent format)")
        ("weights,w",po::value<string>(), "Optional starting weights")
        ("output_every_i_iterations,I",po::value<unsigned>()->default_value(1), "Write weights every I iterations")
        ("regularization_strength,C",po::value<double>()->default_value(1.0), "Regularization strength")
        ("correction_buffers,m", po::value<int>()->default_value(10), "LBFGS correction buffers");
  po::options_description clo("Command line options");
  clo.add_options()
        ("config,c", po::value<string>(&cfg_file), "Configuration file")
        ("help,?", "Print this help message and exit");

  po::options_description dconfig_options, dcmdline_options;
  dconfig_options.add(opts);
  dcmdline_options.add(dconfig_options).add(clo);
  po::store(parse_command_line(argc, argv, dcmdline_options), *conf);
  if (cfg_file.size() > 0) {
    ReadFile rf(cfg_file);
    po::store(po::parse_config_file(*rf.stream(), dconfig_options), *conf);
  }
  if (conf->count("help")) {
    cerr << dcmdline_options << endl;
    exit(1);
  }
}

void AddFeatures(double prob, const SparseVector<double>& fmap, vector<double>* g) {
  for (SparseVector<double>::const_iterator it = fmap.begin(); it != fmap.end(); ++it)
    (*g)[it->first] += it->second * prob;
}

double ApplyRegularizationTerms(const double C,
                                const vector<double>& weights,
                                vector<double>* g) {
  assert(weights.size() == g->size());
  double reg = 0;
  for (size_t i = 0; i < weights.size(); ++i) {
//    const double prev_w_i = (i < prev_weights.size() ? prev_weights[i] : 0.0);
    const double& w_i = weights[i];
    double& g_i = (*g)[i];
    reg += C * w_i * w_i;
    g_i += 2 * C * w_i;

//    reg += T * (w_i - prev_w_i) * (w_i - prev_w_i);
//    g_i += 2 * T * (w_i - prev_w_i);
  }
  return reg;
}

int main(int argc, char** argv) {
  int rank = 0;
  int size = 1;
  po::variables_map conf;
  InitCommandLine(argc, argv, &conf);
  ArcFeatureFunctions ffs;
  vector<TrainingInstance> corpus;
  TrainingInstance::ReadTrainingCorpus(conf["training_data"].as<string>(), &corpus, rank, size);
  vector<ArcFactoredForest> forests(corpus.size());
  SparseVector<double> empirical;
  bool flag = false;
  for (int i = 0; i < corpus.size(); ++i) {
    TrainingInstance& cur = corpus[i];
    if (rank == 0 && (i+1) % 10 == 0) { cerr << '.' << flush; flag = true; }
    if (rank == 0 && (i+1) % 400 == 0) { cerr << " [" << (i+1) << "]\n"; flag = false; }
    ffs.PrepareForInput(cur.ts);
    SparseVector<weight_t> efmap;
    for (int j = 0; j < cur.tree.h_m_pairs.size(); ++j) {
      efmap.clear();
      ffs.EdgeFeatures(cur.ts, cur.tree.h_m_pairs[j].first,
                       cur.tree.h_m_pairs[j].second,
                       &efmap);
      cur.features += efmap;
    }
    for (int j = 0; j < cur.tree.roots.size(); ++j) {
      efmap.clear();
      ffs.EdgeFeatures(cur.ts, -1, cur.tree.roots[j], &efmap);
      cur.features += efmap;
    }
    empirical += cur.features;
    forests[i].resize(cur.ts.words.size());
    forests[i].ExtractFeatures(cur.ts, ffs);
  }
  if (flag) cerr << endl;
  //cerr << "EMP: " << empirical << endl; //DE
  vector<weight_t> weights(FD::NumFeats(), 0.0);
  if (conf.count("weights"))
    Weights::InitFromFile(conf["weights"].as<string>(), &weights);
  vector<weight_t> g(FD::NumFeats(), 0.0);
  cerr << "features initialized\noptimizing...\n";
  boost::shared_ptr<BatchOptimizer> o;
  int every = corpus.size() / 20;
  if (!every) ++every;
  o.reset(new LBFGSOptimizer(g.size(), conf["correction_buffers"].as<int>()));
  int iterations = 1000;
  for (int iter = 0; iter < iterations; ++iter) {
    cerr << "ITERATION " << iter << " " << flush;
    fill(g.begin(), g.end(), 0.0);
    for (SparseVector<double>::const_iterator it = empirical.begin(); it != empirical.end(); ++it)
      g[it->first] = -it->second;
    double obj = -empirical.dot(weights);
    // SparseVector<double> mfm;  //DE
    for (int i = 0; i < corpus.size(); ++i) {
      if ((i + 1) % every == 0) cerr << '.' << flush;
      const int num_words = corpus[i].ts.words.size();
      forests[i].Reweight(weights);
      prob_t z;
      forests[i].EdgeMarginals(&z);
      obj -= log(z);
      //cerr << " O = " << (-corpus[i].features.dot(weights)) << " D=" << -lz << "  OO= " << (-corpus[i].features.dot(weights) - lz) << endl;
      //cerr << " ZZ = " << zz << endl;
      for (int h = -1; h < num_words; ++h) {
        for (int m = 0; m < num_words; ++m) {
          if (h == m) continue;
          const ArcFactoredForest::Edge& edge = forests[i](h,m);
          const SparseVector<weight_t>& fmap = edge.features;
          double prob = edge.edge_prob.as_float();
          if (prob < -0.000001) { cerr << "Prob < 0: " << prob << endl; prob = 0; }
          if (prob > 1.000001) { cerr << "Prob > 1: " << prob << endl; prob = 1; }
          AddFeatures(prob, fmap, &g);
          //mfm += fmap * prob;  // DE
        }
      }
    }
    //cerr << endl << "E: " << empirical << endl;  // DE
    //cerr << "M: " << mfm << endl;  // DE
    double r = ApplyRegularizationTerms(conf["regularization_strength"].as<double>(), weights, &g);
    double gnorm = 0;
    for (int i = 0; i < g.size(); ++i)
      gnorm += g[i]*g[i];
    ostringstream ll;
    ll << "ITER=" << (iter+1) << "\tOBJ=" << (obj+r) << "\t[F=" << obj << " R=" << r << "]\tGnorm=" << sqrt(gnorm);
    cerr << ' ' << ll.str().substr(ll.str().find('\t')+1) << endl;
    obj += r;
    assert(obj >= 0);
    o->Optimize(obj, g, &weights);
    Weights::ShowLargestFeatures(weights);
    const bool converged = o->HasConverged();
    const char* ofname = converged ? "weights.final.gz" : "weights.cur.gz";
    if (converged || ((iter+1) % conf["output_every_i_iterations"].as<unsigned>()) == 0) {
      cerr << "writing..." << flush;
      const string sl = ll.str();
      Weights::WriteToFile(ofname, weights, true, &sl);
      cerr << "done" << endl;
    }
    if (converged) { cerr << "CONVERGED\n"; break; }
  }
  return 0;
}

<commit_msg>parallel gradient computation<commit_after>#include "arc_factored.h"

#include <vector>
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/program_options/variables_map.hpp>
// #define HAVE_THREAD 1
#if HAVE_THREAD
#include <boost/thread.hpp>
#endif

#include "arc_ff.h"
#include "stringlib.h"
#include "filelib.h"
#include "tdict.h"
#include "dep_training.h"
#include "optimize.h"
#include "weights.h"

using namespace std;
namespace po = boost::program_options;

void InitCommandLine(int argc, char** argv, po::variables_map* conf) {
  po::options_description opts("Configuration options");
  string cfg_file;
  opts.add_options()
        ("training_data,t",po::value<string>()->default_value("-"), "File containing training data (jsent format)")
        ("weights,w",po::value<string>(), "Optional starting weights")
        ("output_every_i_iterations,I",po::value<unsigned>()->default_value(1), "Write weights every I iterations")
        ("regularization_strength,C",po::value<double>()->default_value(1.0), "Regularization strength")
#if HAVE_THREAD
        ("threads,T",po::value<unsigned>()->default_value(1), "Number of threads")
#endif
        ("correction_buffers,m", po::value<int>()->default_value(10), "LBFGS correction buffers");
  po::options_description clo("Command line options");
  clo.add_options()
        ("config,c", po::value<string>(&cfg_file), "Configuration file")
        ("help,?", "Print this help message and exit");

  po::options_description dconfig_options, dcmdline_options;
  dconfig_options.add(opts);
  dcmdline_options.add(dconfig_options).add(clo);
  po::store(parse_command_line(argc, argv, dcmdline_options), *conf);
  if (cfg_file.size() > 0) {
    ReadFile rf(cfg_file);
    po::store(po::parse_config_file(*rf.stream(), dconfig_options), *conf);
  }
  if (conf->count("help")) {
    cerr << dcmdline_options << endl;
    exit(1);
  }
}

void AddFeatures(double prob, const SparseVector<double>& fmap, vector<double>* g) {
  for (SparseVector<double>::const_iterator it = fmap.begin(); it != fmap.end(); ++it)
    (*g)[it->first] += it->second * prob;
}

double ApplyRegularizationTerms(const double C,
                                const vector<double>& weights,
                                vector<double>* g) {
  assert(weights.size() == g->size());
  double reg = 0;
  for (size_t i = 0; i < weights.size(); ++i) {
//    const double prev_w_i = (i < prev_weights.size() ? prev_weights[i] : 0.0);
    const double& w_i = weights[i];
    double& g_i = (*g)[i];
    reg += C * w_i * w_i;
    g_i += 2 * C * w_i;

//    reg += T * (w_i - prev_w_i) * (w_i - prev_w_i);
//    g_i += 2 * T * (w_i - prev_w_i);
  }
  return reg;
}

struct GradientWorker {
  GradientWorker(int f,
                 int t,
                 vector<double>* w,
                 vector<TrainingInstance>* c,
                 vector<ArcFactoredForest>* fs) : obj(), weights(*w), from(f), to(t), corpus(*c), forests(*fs), g(w->size()) {}
  void operator()() {
    int every = (to - from) / 20;
    if (!every) every++;
    for (int i = from; i < to; ++i) {
      if ((from == 0) && (i + 1) % every == 0) cerr << '.' << flush;
      const int num_words = corpus[i].ts.words.size();
      forests[i].Reweight(weights);
      prob_t z;
      forests[i].EdgeMarginals(&z);
      obj -= log(z);
      //cerr << " O = " << (-corpus[i].features.dot(weights)) << " D=" << -lz << "  OO= " << (-corpus[i].features.dot(weights) - lz) << endl;
      //cerr << " ZZ = " << zz << endl;
      for (int h = -1; h < num_words; ++h) {
        for (int m = 0; m < num_words; ++m) {
          if (h == m) continue;
          const ArcFactoredForest::Edge& edge = forests[i](h,m);
          const SparseVector<weight_t>& fmap = edge.features;
          double prob = edge.edge_prob.as_float();
          if (prob < -0.000001) { cerr << "Prob < 0: " << prob << endl; prob = 0; }
          if (prob > 1.000001) { cerr << "Prob > 1: " << prob << endl; prob = 1; }
          AddFeatures(prob, fmap, &g);
          //mfm += fmap * prob;  // DE
        }
      }
    }
  }
  double obj;
  vector<double>& weights;
  const int from, to;
  vector<TrainingInstance>& corpus;
  vector<ArcFactoredForest>& forests;
  vector<double> g; // local gradient
};

int main(int argc, char** argv) {
  int rank = 0;
  int size = 1;
  po::variables_map conf;
  InitCommandLine(argc, argv, &conf);
  ArcFeatureFunctions ffs;
  vector<TrainingInstance> corpus;
  TrainingInstance::ReadTrainingCorpus(conf["training_data"].as<string>(), &corpus, rank, size);
  vector<ArcFactoredForest> forests(corpus.size());
  SparseVector<double> empirical;
  bool flag = false;
  for (int i = 0; i < corpus.size(); ++i) {
    TrainingInstance& cur = corpus[i];
    if (rank == 0 && (i+1) % 10 == 0) { cerr << '.' << flush; flag = true; }
    if (rank == 0 && (i+1) % 400 == 0) { cerr << " [" << (i+1) << "]\n"; flag = false; }
    ffs.PrepareForInput(cur.ts);
    SparseVector<weight_t> efmap;
    for (int j = 0; j < cur.tree.h_m_pairs.size(); ++j) {
      efmap.clear();
      ffs.EdgeFeatures(cur.ts, cur.tree.h_m_pairs[j].first,
                       cur.tree.h_m_pairs[j].second,
                       &efmap);
      cur.features += efmap;
    }
    for (int j = 0; j < cur.tree.roots.size(); ++j) {
      efmap.clear();
      ffs.EdgeFeatures(cur.ts, -1, cur.tree.roots[j], &efmap);
      cur.features += efmap;
    }
    empirical += cur.features;
    forests[i].resize(cur.ts.words.size());
    forests[i].ExtractFeatures(cur.ts, ffs);
  }
  if (flag) cerr << endl;
  //cerr << "EMP: " << empirical << endl; //DE
  vector<weight_t> weights(FD::NumFeats(), 0.0);
  if (conf.count("weights"))
    Weights::InitFromFile(conf["weights"].as<string>(), &weights);
  vector<weight_t> g(FD::NumFeats(), 0.0);
  cerr << "features initialized\noptimizing...\n";
  boost::shared_ptr<BatchOptimizer> o;
#if HAVE_THREAD
  unsigned threads = conf["threads"].as<unsigned>();
  if (threads > corpus.size()) threads = corpus.size();
#else
  const unsigned threads = 1;
#endif
  int chunk = corpus.size() / threads;
  o.reset(new LBFGSOptimizer(g.size(), conf["correction_buffers"].as<int>()));
  int iterations = 1000;
  for (int iter = 0; iter < iterations; ++iter) {
    cerr << "ITERATION " << iter << " " << flush;
    fill(g.begin(), g.end(), 0.0);
    for (SparseVector<double>::const_iterator it = empirical.begin(); it != empirical.end(); ++it)
      g[it->first] = -it->second;
    double obj = -empirical.dot(weights);
    vector<boost::shared_ptr<GradientWorker> > jobs;
    for (int from = 0; from < corpus.size(); from += chunk) {
      int to = from + chunk;
      if (to > corpus.size()) to = corpus.size();
      jobs.push_back(boost::shared_ptr<GradientWorker>(new GradientWorker(from, to, &weights, &corpus, &forests)));
    }
#if HAVE_THREAD
    boost::thread_group tg;
    for (int i = 0; i < threads; ++i)
      tg.create_thread(boost::ref(*jobs[i]));
    tg.join_all();
#else
    (*jobs[0])();
#endif
    for (int i = 0; i < threads; ++i) {
      obj += jobs[i]->obj;
      vector<double>& tg = jobs[i]->g;
      for (unsigned j = 0; j < g.size(); ++j)
        g[j] += tg[j];
    }
    // SparseVector<double> mfm;  //DE
    //cerr << endl << "E: " << empirical << endl;  // DE
    //cerr << "M: " << mfm << endl;  // DE
    double r = ApplyRegularizationTerms(conf["regularization_strength"].as<double>(), weights, &g);
    double gnorm = 0;
    for (int i = 0; i < g.size(); ++i)
      gnorm += g[i]*g[i];
    ostringstream ll;
    ll << "ITER=" << (iter+1) << "\tOBJ=" << (obj+r) << "\t[F=" << obj << " R=" << r << "]\tGnorm=" << sqrt(gnorm);
    cerr << ' ' << ll.str().substr(ll.str().find('\t')+1) << endl;
    obj += r;
    assert(obj >= 0);
    o->Optimize(obj, g, &weights);
    Weights::ShowLargestFeatures(weights);
    const bool converged = o->HasConverged();
    const char* ofname = converged ? "weights.final.gz" : "weights.cur.gz";
    if (converged || ((iter+1) % conf["output_every_i_iterations"].as<unsigned>()) == 0) {
      cerr << "writing..." << flush;
      const string sl = ll.str();
      Weights::WriteToFile(ofname, weights, true, &sl);
      cerr << "done" << endl;
    }
    if (converged) { cerr << "CONVERGED\n"; break; }
  }
  return 0;
}

<|endoftext|>


<commit_before>
/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Miodrag Milanovic <miodrag@symbioticeda.com>
 *  Copyright (C) 2018  Serge Bazanski <q3k@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "application.h"
#include <QMessageBox>
#include <QSurfaceFormat>
#include <QTextStream>
#include <exception>

NEXTPNR_NAMESPACE_BEGIN

#ifdef _WIN32
#include <windows.h>
BOOL WINAPI WinHandler(DWORD dwCtrlType)
{
    if (dwCtrlType == CTRL_C_EVENT)
        qApp->quit();
    return TRUE;
}
#endif

Application::Application(int &argc, char **argv) : QApplication(argc, argv)
{
    QSurfaceFormat fmt;
    fmt.setSamples(10);
    fmt.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(fmt);
#ifdef _WIN32
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE);
#endif
}

bool Application::notify(QObject *receiver, QEvent *event)
{
    bool retVal = true;
    try {
        retVal = QApplication::notify(receiver, event);
    } catch (assertion_failure ex) {
        QString msg;
        QTextStream out(&msg);
        out << ex.filename.c_str() << " at " << ex.line << "\n";
        out << ex.msg.c_str();
        QMessageBox::critical(0, "Error", msg);
    } catch (...) {
        QMessageBox::critical(0, "Error", "Fatal error !!!");
    }
    return retVal;
}

NEXTPNR_NAMESPACE_END
<commit_msg>gui: Fix warning: catching polymorphic type by value<commit_after>
/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Miodrag Milanovic <miodrag@symbioticeda.com>
 *  Copyright (C) 2018  Serge Bazanski <q3k@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "application.h"
#include <QMessageBox>
#include <QSurfaceFormat>
#include <QTextStream>
#include <exception>

NEXTPNR_NAMESPACE_BEGIN

#ifdef _WIN32
#include <windows.h>
BOOL WINAPI WinHandler(DWORD dwCtrlType)
{
    if (dwCtrlType == CTRL_C_EVENT)
        qApp->quit();
    return TRUE;
}
#endif

Application::Application(int &argc, char **argv) : QApplication(argc, argv)
{
    QSurfaceFormat fmt;
    fmt.setSamples(10);
    fmt.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(fmt);
#ifdef _WIN32
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE);
#endif
}

bool Application::notify(QObject *receiver, QEvent *event)
{
    bool retVal = true;
    try {
        retVal = QApplication::notify(receiver, event);
    } catch (const assertion_failure &ex) {
        QString msg;
        QTextStream out(&msg);
        out << ex.filename.c_str() << " at " << ex.line << "\n";
        out << ex.msg.c_str();
        QMessageBox::critical(0, "Error", msg);
    } catch (...) {
        QMessageBox::critical(0, "Error", "Fatal error !!!");
    }
    return retVal;
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>/*
    Copyright (C) 2016  P.L. Lucas <selairi@gmail.com>

    This library 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; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "xrandrbrightness.h"
#include <QDebug>
#include <LXQt/SingleApplication>
#include <QCommandLineParser>
#include "brightnesssettings.h"

int main(int argn, char* argv[])
{
    LXQt::SingleApplication app(argn, argv);

    // Command line options
    QCommandLineParser parser;
    QCommandLineOption increaseOption(QStringList() << "i" << "icrease",
            app.tr("Increase brightness."));
    parser.addOption(increaseOption);
    QCommandLineOption decreaseOption(QStringList() << "d" << "decrease",
            app.tr("Decrease brightness."));
    parser.addOption(decreaseOption);
    QCommandLineOption helpOption = parser.addHelpOption();
    parser.addOption(increaseOption);
    parser.addOption(decreaseOption);
    parser.addOption(helpOption);

    parser.process(app);
    if( parser.isSet(increaseOption) || parser.isSet(decreaseOption) )
    {
        XRandrBrightness *brightness = new XRandrBrightness();
        QList<MonitorInfo> monitors = brightness->getMonitorsInfo();
        QList<MonitorInfo> monitorsChanged;
        float sign = parser.isSet(decreaseOption)?-1.0:1.0;
        foreach(MonitorInfo monitor, monitors)
        {

            if( monitor.isBacklightSupported() )
            {
                long backlight = monitor.backlight() + sign*(monitor.backlightMax()/30 + 1);
                if(backlight<monitor.backlightMax())
                {
                    monitor.setBacklight(backlight);
                    monitorsChanged.append(monitor);
                }
            }
            else
            {
                float brightness = monitor.brightness() + 0.1*sign;
                if(brightness<2.0)
                {
                    monitor.setBrightness(brightness);
                    monitorsChanged.append(monitor);
                }
            }
        }
        brightness->setMonitorsSettings(monitorsChanged);
        return 0;
    }

    BrightnessSettings *brightnessSettings = new BrightnessSettings();
    brightnessSettings->setWindowIcon(QIcon(ICON_DIR "/brightnesssettings.svg"));
    brightnessSettings->show();

    return app.exec();
}

<commit_msg>lxqt-config-brigness: Set brightness value by command line.<commit_after>/*
    Copyright (C) 2016  P.L. Lucas <selairi@gmail.com>

    This library 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; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "xrandrbrightness.h"
#include <QDebug>
#include <LXQt/SingleApplication>
#include <QCommandLineParser>
#include "brightnesssettings.h"

int main(int argn, char* argv[])
{
    LXQt::SingleApplication app(argn, argv);

    // Command line options
    QCommandLineParser parser;
    QCommandLineOption increaseOption(QStringList() << "i" << "icrease",
            app.tr("Increase brightness."));
    parser.addOption(increaseOption);
    QCommandLineOption decreaseOption(QStringList() << "d" << "decrease",
            app.tr("Decrease brightness."));
    parser.addOption(decreaseOption);
    QCommandLineOption setOption(QStringList() << "s" << "set",
            app.tr("Set brightness from 1 to 100."), "brightness");
    parser.addOption(setOption);
    QCommandLineOption helpOption = parser.addHelpOption();
    parser.addOption(increaseOption);
    parser.addOption(decreaseOption);
    parser.addOption(setOption);
    parser.addOption(helpOption);

    parser.process(app);
    if( parser.isSet(increaseOption) || parser.isSet(decreaseOption) || parser.isSet(setOption) )
    {
        XRandrBrightness *brightness = new XRandrBrightness();
        QList<MonitorInfo> monitors = brightness->getMonitorsInfo();
        QList<MonitorInfo> monitorsChanged;
        float sign = parser.isSet(decreaseOption)?-1.0:1.0;
        double brightness_value = parser.value(setOption).toFloat();
        brightness_value = qMin( qMax(brightness_value, 0.0), 100.0 ) / 100.0;
        if(!parser.value(setOption).isEmpty())
            sign = 0.0;
        foreach(MonitorInfo monitor, monitors)
        {

            if( monitor.isBacklightSupported() )
            {
                long backlight = ( monitor.backlight() + sign*(monitor.backlightMax()/50 + 1) )*qAbs(sign) + brightness_value*monitor.backlightMax();
                if(backlight<monitor.backlightMax() && backlight>0)
                {
                    monitor.setBacklight(backlight);
                    monitorsChanged.append(monitor);
                }
            }
            else
            {
                float brightness = (monitor.brightness() + 0.1*sign)*qAbs(sign) + brightness_value*2.0;
                if(brightness<2.0 && brightness>0.0)
                {
                    monitor.setBrightness(brightness);
                    monitorsChanged.append(monitor);
                }
            }
        }
        brightness->setMonitorsSettings(monitorsChanged);
        return 0;
    }

    BrightnessSettings *brightnessSettings = new BrightnessSettings();
    brightnessSettings->setWindowIcon(QIcon(ICON_DIR "/brightnesssettings.svg"));
    brightnessSettings->show();

    return app.exec();
}

<|endoftext|>


<commit_before>#include "nif_utils.h"
#include "erlcass.h"
#include "serialization.hpp"

#include <string.h>

ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name)
{
    ERL_NIF_TERM ret;

    if(enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1))
        return ret;

    return enif_make_atom(env, name);
}

ERL_NIF_TERM make_binary(ErlNifEnv* env, const char* buff, size_t length)
{
    ERL_NIF_TERM term;
    unsigned char *destination_buffer = enif_make_new_binary(env, length, &term);
    memcpy(destination_buffer, buff, length);
    return term;
}

ERL_NIF_TERM make_error(ErlNifEnv* env, const char* error)
{
    return enif_make_tuple2(env, ATOMS.atomError, make_binary(env, error, strlen(error)));
}

bool get_atom(ErlNifEnv* env, ERL_NIF_TERM term, std::string & value)
{
    unsigned len;

    if(!enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1))
        return false;

    value.resize(len+1);
    return enif_get_atom(env, term, &*(value.begin()), len+1, ERL_NIF_LATIN1);
}

bool get_string(ErlNifEnv* env, ERL_NIF_TERM term, std::string & value)
{
    if(enif_is_binary(env, term))
    {
        ErlNifBinary bin;

        if(enif_inspect_binary(env, term, &bin))
        {
            value.resize(bin.size);
            memcpy((char*)value.c_str(), bin.data, bin.size);
            return true;
        }
    }
    else
    {
        unsigned len;
        bool ret = enif_get_list_length(env, term, &len);

        if(ret)
        {
            value.resize(len+1);
            ret =  enif_get_string(env, term, &*(value.begin()), value.size(), ERL_NIF_LATIN1);

            if(ret > 0)
                value.resize(len); //trim null terminated char.
        }

        return ret;
    }

    return false;
}

ERL_NIF_TERM cass_error_to_nif_term(ErlNifEnv* env, CassError error)
{
    if(error != CASS_OK)
        return make_error(env, cass_error_desc(error));

    return ATOMS.atomOk;
}

ERL_NIF_TERM cass_future_error_to_nif_term(ErlNifEnv* env, CassFuture* future)
{
    const char* message;
    size_t message_length;
    cass_future_error_message(future, &message, &message_length);

    std::string msg(message, message_length);
    return make_error(env, msg.c_str());
}
<commit_msg>Remove useless include<commit_after>#include "nif_utils.h"
#include "erlcass.h"

#include <string.h>

ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name)
{
    ERL_NIF_TERM ret;

    if(enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1))
        return ret;

    return enif_make_atom(env, name);
}

ERL_NIF_TERM make_binary(ErlNifEnv* env, const char* buff, size_t length)
{
    ERL_NIF_TERM term;
    unsigned char *destination_buffer = enif_make_new_binary(env, length, &term);
    memcpy(destination_buffer, buff, length);
    return term;
}

ERL_NIF_TERM make_error(ErlNifEnv* env, const char* error)
{
    return enif_make_tuple2(env, ATOMS.atomError, make_binary(env, error, strlen(error)));
}

bool get_atom(ErlNifEnv* env, ERL_NIF_TERM term, std::string & value)
{
    unsigned len;

    if(!enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1))
        return false;

    value.resize(len+1);
    return enif_get_atom(env, term, &*(value.begin()), len+1, ERL_NIF_LATIN1);
}

bool get_string(ErlNifEnv* env, ERL_NIF_TERM term, std::string & value)
{
    if(enif_is_binary(env, term))
    {
        ErlNifBinary bin;

        if(enif_inspect_binary(env, term, &bin))
        {
            value.resize(bin.size);
            memcpy((char*)value.c_str(), bin.data, bin.size);
            return true;
        }
    }
    else
    {
        unsigned len;
        bool ret = enif_get_list_length(env, term, &len);

        if(ret)
        {
            value.resize(len+1);
            ret =  enif_get_string(env, term, &*(value.begin()), value.size(), ERL_NIF_LATIN1);

            if(ret > 0)
                value.resize(len); //trim null terminated char.
        }

        return ret;
    }

    return false;
}

ERL_NIF_TERM cass_error_to_nif_term(ErlNifEnv* env, CassError error)
{
    if(error != CASS_OK)
        return make_error(env, cass_error_desc(error));

    return ATOMS.atomOk;
}

ERL_NIF_TERM cass_future_error_to_nif_term(ErlNifEnv* env, CassFuture* future)
{
    const char* message;
    size_t message_length;
    cass_future_error_message(future, &message, &message_length);

    std::string msg(message, message_length);
    return make_error(env, msg.c_str());
}
<|endoftext|>


<commit_before>#include <cstdint>
#include <cstddef>
#include "OpenEXR/ImathVec.h"
#include "OpenEXR/ImathBox.h"
#include "OpenEXR/ImfPixelType.h"
#include "OpenEXR/ImfChannelList.h"
#include "OpenEXR/ImfHeader.h"
#include "OpenEXR/ImfFrameBuffer.h"
#include "OpenEXR/ImfOutputFile.h"
#include "OpenEXR/ImfInputFile.h"

using namespace IMATH_NAMESPACE;
using namespace Imf;

extern "C" {
    // PixelType
    // This is a stand-in for an enum from the C++ library.
    // 0: u32
    // 1: f16
    // 2: f32
    typedef int CEXR_PixelType;

    // CompressionMethod
    // This is a stand-in for an enum from the C++ library.
    // 0 = NO_COMPRESSION
    // 1 = RLE_COMPRESSION
    // 2 = ZIPS_COMPRESSION
    // 3 = ZIP_COMPRESSION
    // 4 = PIZ_COMPRESSION
    // 5 = PXR24_COMPRESSION
    // 6 = B44_COMPRESSION
    // 7 = B44A_COMPRESSION
    // 8 = DWAA_COMPRESSION
    // 9 = DWAB_COMPRESSION
    typedef int CEXR_CompressionMethod;

    // Channel
    // This isn't a wrapper per se, but an separate representation for
    // passing to/from Rust.
    struct CEXR_Channel {
        CEXR_PixelType type; // enum
        int x_sampling;
        int y_sampling;
        int p_linear; // bool
    };
};

//------------------------------------------------------------------------------
// Channel iterator
extern "C" {
    struct CEXR_ChannelIterator {
        void *begin;
        void *end;
    };

    void CEXR_ChannelIterator_delete(
        CEXR_ChannelIterator *iterator);

    const char * CEXR_ChannelIterator_next(
        CEXR_ChannelIterator* iterator);
};

void CEXR_ChannelIterator_delete(CEXR_ChannelIterator *iterator) {
    auto begin_ptr = reinterpret_cast<ChannelList::Iterator*>(iterator->begin);
    auto end_ptr = reinterpret_cast<ChannelList::Iterator*>(iterator->end);
    delete begin_ptr;
    delete end_ptr;
}

// Returns nullptr if no more channels
const char * CEXR_ChannelIterator_next(CEXR_ChannelIterator* iterator) {
    auto &begin = *reinterpret_cast<ChannelList::Iterator*>(iterator->begin);
    auto &end = *reinterpret_cast<ChannelList::Iterator*>(iterator->end);

    if (begin == end) {
        return nullptr;
    }

    auto name = begin.name();
    begin++;
    return name;
}

//------------------------------------------------------------------------------
// EXR header type.
extern "C" {
    struct CEXR_Header {
        void *header;
    };

    CEXR_Header CEXR_Header_new(
        int display_window_min_x,
        int display_window_min_y,
        int display_window_max_x,
        int display_window_max_y,
        int data_window_min_x,
        int data_window_min_y,
        int data_window_max_x,
        int data_window_max_y,
        float pixel_aspect_ratio,
        float screen_window_center_x,
        float screen_window_center_y,
        float screen_window_width,
        int line_order, // 0: INCREASING_Y, 1: DECREASING_Y, 2: RANDOM_Y
        CEXR_CompressionMethod compression);

    void CEXR_Header_delete(
        CEXR_Header *header);

    void CEXR_Header_insert_channel(
        CEXR_Header *header,
        const char name[],
        const CEXR_Channel channel);

    int CEXR_Header_channel_exists(
        CEXR_Header *header,
        const char name[]);

    CEXR_Channel CEXR_Header_get_channel(
        CEXR_Header *header,
        const char name[]);

    CEXR_ChannelIterator CEXR_Header_new_channel_iterator(
        CEXR_Header *header);
};

CEXR_Header CEXR_Header_new(
    int display_window_min_x,
    int display_window_min_y,
    int display_window_max_x,
    int display_window_max_y,
    int data_window_min_x,
    int data_window_min_y,
    int data_window_max_x,
    int data_window_max_y,
    float pixel_aspect_ratio,
    float screen_window_center_x,
    float screen_window_center_y,
    float screen_window_width,
    int line_order,
    int compression
) {
    CEXR_Header header;

    header.header = new Header(
        Box2i(V2i(display_window_min_x, display_window_min_y), V2i(display_window_max_x, display_window_max_y)),
        Box2i(V2i(data_window_min_x, data_window_min_y), V2i(data_window_max_x, data_window_max_y)),
        pixel_aspect_ratio,
        V2f(screen_window_center_x, screen_window_center_y),
        screen_window_width,
        static_cast<LineOrder>(line_order),
        static_cast<Compression>(compression));
    return header;
}

void CEXR_Header_delete(CEXR_Header *header) {
    auto h = reinterpret_cast<Header*>(header->header);
    delete h;
}

void CEXR_Header_insert_channel(CEXR_Header *header, const char name[], const CEXR_Channel channel) {
    auto h = reinterpret_cast<Header*>(header->header);
    h->channels().insert(
        name,
        Channel(
            static_cast<PixelType>(channel.type),
            channel.x_sampling,
            channel.y_sampling,
            channel.p_linear));
}

int CEXR_Header_channel_exists(CEXR_Header *header, const char name[]) {
    auto h = reinterpret_cast<Header*>(header->header);
    h->channels().findChannel(name) != 0;
}

CEXR_Channel CEXR_Header_get_channel(CEXR_Header *header, const char name[]) {
    auto h = reinterpret_cast<Header*>(header->header);
    auto chan = h->channels().findChannel(name);

    CEXR_Channel channel;
    channel.type = chan->type;
    channel.x_sampling = chan->xSampling;
    channel.y_sampling = chan->ySampling;
    channel.p_linear = chan->pLinear;

    return channel;
}

CEXR_ChannelIterator CEXR_Header_new_channel_iterator(CEXR_Header *header) {
    auto h = reinterpret_cast<Header*>(header->header);

    CEXR_ChannelIterator channel_iter;
    channel_iter.begin = reinterpret_cast<void*>(new auto(h->channels().begin()));
    channel_iter.end = reinterpret_cast<void*>(new auto(h->channels().end()));

    return channel_iter;
}

//------------------------------------------------------------------------------
// FrameBuffer
extern "C" {
    struct CEXR_FrameBuffer {
        void *frame_buffer;
    };

    CEXR_FrameBuffer CEXR_FrameBuffer_new();

    void CEXR_FrameBuffer_delete(
        CEXR_FrameBuffer *frame_buffer);

    void CEXR_FrameBuffer_insert_slice(
        CEXR_FrameBuffer *frame_buffer,
        const char name[],
        char *base,
        size_t x_stride,
        size_t y_stride,
        int x_sampling,
        int y_sampling,
        double fill_value,
        int x_tile_coords, // bool
        int y_tile_coords // bool
        );
};

CEXR_FrameBuffer CEXR_FrameBuffer_new() {
    CEXR_FrameBuffer buffer;

    buffer.frame_buffer = reinterpret_cast<void*>(new FrameBuffer());

    return buffer;
}

void CEXR_FrameBuffer_delete(CEXR_FrameBuffer *frame_buffer) {
    auto buffer = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);
    delete buffer;
}

void CEXR_FrameBuffer_insert_slice(
    CEXR_FrameBuffer *frame_buffer,
    const char name[],
    CEXR_PixelType type,
    char *base,
    size_t x_stride,
    size_t y_stride,
    int x_sampling,
    int y_sampling,
    double fill_value,
    int x_tile_coords, // bool
    int y_tile_coords // bool
) {
    auto buffer = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);

    Slice slice;
    slice.type = static_cast<PixelType>(type);
    slice.base = base;
    slice.xStride = x_stride;
    slice.yStride = y_stride;
    slice.xSampling = x_sampling;
    slice.ySampling = y_sampling;
    slice.fillValue = fill_value;
    slice.xTileCoords = x_tile_coords;
    slice.yTileCoords = y_tile_coords;

    buffer->insert(name, slice);
}

//------------------------------------------------------------------------------
// OutputFile
extern "C" {
    struct CEXR_OutputFile {
        void *output_file;
    };

    CEXR_OutputFile CEXR_OutputFile_new(
        const char * file_name,
        const CEXR_Header *header,
        int num_threads);

    void CEXR_OutputFile_delete(
        CEXR_OutputFile *output_file);

    void CEXR_OutputFile_set_frame_buffer(
        CEXR_OutputFile* output_file,
        CEXR_FrameBuffer* frame_buffer);

    void CEXR_OutputFile_write_pixels(
        CEXR_OutputFile* output_file,
        int num_scan_lines);
};

CEXR_OutputFile CEXR_OutputFile_new(const char * file_name, const CEXR_Header *header, int num_threads) {
    CEXR_OutputFile output_file;

    output_file.output_file = reinterpret_cast<void*>(new OutputFile(
        file_name,
        *reinterpret_cast<Header*>(header->header),
        num_threads
    ));

    return output_file;
}

void CEXR_OutputFile_delete(CEXR_OutputFile *output_file) {
    auto outfile = reinterpret_cast<OutputFile*>(output_file->output_file);

    delete outfile;
}

void CEXR_OutputFile_set_frame_buffer(CEXR_OutputFile* output_file, CEXR_FrameBuffer* frame_buffer) {
    auto outfile = reinterpret_cast<OutputFile*>(output_file->output_file);
    auto framebuf = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);

    outfile->setFrameBuffer(*framebuf);
}

void CEXR_OutputFile_write_pixels(CEXR_OutputFile* output_file, int num_scan_lines) {
    auto outfile = reinterpret_cast<OutputFile*>(output_file->output_file);

    outfile->writePixels(num_scan_lines);
}

// //------------------------------------------------------------------------------
// // InputFile
// extern "C" {
//     struct CEXR_InputFile {
//         CEXR_Header header;
//         void *input_file;
//     };
//
//     CEXR_InputFile CEXR_InputFile_new(
//         const char file_name[],
//         int num_threads);
//
//     void CEXR_InputFile_delete(
//         CEXR_InputFile *input_file);
//
//     const CEXR_Header *CEXR_InputFile_header(
//         const CEXR_InputFile *input_file);
//
//     int CEXR_InputFile_version(
//         const CEXR_InputFile *input_file);
//
//     void CEXR_InputFile_set_frame_buffer(
//         CEXR_InputFile* input_file,
//         CEXR_FrameBuffer* frame_buffer);
//
//     int CEXR_InputFile_is_complete(
//         const CEXR_InputFile *input_file);
//
//     void CEXR_InputFile_read_pixels(
//         CEXR_InputFile *input_file,
//         int scanline_1,
//         int scanline_2);
// };
<commit_msg>Wrapped InputFile for C.<commit_after>#include <cstdint>
#include <cstddef>
#include "OpenEXR/ImathVec.h"
#include "OpenEXR/ImathBox.h"
#include "OpenEXR/ImfPixelType.h"
#include "OpenEXR/ImfChannelList.h"
#include "OpenEXR/ImfHeader.h"
#include "OpenEXR/ImfFrameBuffer.h"
#include "OpenEXR/ImfOutputFile.h"
#include "OpenEXR/ImfInputFile.h"

using namespace IMATH_NAMESPACE;
using namespace Imf;

extern "C" {
    // PixelType
    // This is a stand-in for an enum from the C++ library.
    // 0: u32
    // 1: f16
    // 2: f32
    typedef int CEXR_PixelType;

    // CompressionMethod
    // This is a stand-in for an enum from the C++ library.
    // 0 = NO_COMPRESSION
    // 1 = RLE_COMPRESSION
    // 2 = ZIPS_COMPRESSION
    // 3 = ZIP_COMPRESSION
    // 4 = PIZ_COMPRESSION
    // 5 = PXR24_COMPRESSION
    // 6 = B44_COMPRESSION
    // 7 = B44A_COMPRESSION
    // 8 = DWAA_COMPRESSION
    // 9 = DWAB_COMPRESSION
    typedef int CEXR_CompressionMethod;

    // Channel
    // This isn't a wrapper per se, but an separate representation for
    // passing to/from Rust.
    struct CEXR_Channel {
        CEXR_PixelType type; // enum
        int x_sampling;
        int y_sampling;
        int p_linear; // bool
    };
};

//------------------------------------------------------------------------------
// Channel iterator
extern "C" {
    struct CEXR_ChannelIterator {
        void *begin;
        void *end;
    };

    void CEXR_ChannelIterator_delete(
        CEXR_ChannelIterator *iterator);

    const char * CEXR_ChannelIterator_next(
        CEXR_ChannelIterator* iterator);
};

void CEXR_ChannelIterator_delete(CEXR_ChannelIterator *iterator) {
    auto begin_ptr = reinterpret_cast<ChannelList::Iterator*>(iterator->begin);
    auto end_ptr = reinterpret_cast<ChannelList::Iterator*>(iterator->end);
    delete begin_ptr;
    delete end_ptr;
}

// Returns nullptr if no more channels
const char * CEXR_ChannelIterator_next(CEXR_ChannelIterator* iterator) {
    auto &begin = *reinterpret_cast<ChannelList::Iterator*>(iterator->begin);
    auto &end = *reinterpret_cast<ChannelList::Iterator*>(iterator->end);

    if (begin == end) {
        return nullptr;
    }

    auto name = begin.name();
    begin++;
    return name;
}

//------------------------------------------------------------------------------
// EXR header type.
extern "C" {
    struct CEXR_Header {
        void *header;
    };

    CEXR_Header CEXR_Header_new(
        int display_window_min_x,
        int display_window_min_y,
        int display_window_max_x,
        int display_window_max_y,
        int data_window_min_x,
        int data_window_min_y,
        int data_window_max_x,
        int data_window_max_y,
        float pixel_aspect_ratio,
        float screen_window_center_x,
        float screen_window_center_y,
        float screen_window_width,
        int line_order, // 0: INCREASING_Y, 1: DECREASING_Y, 2: RANDOM_Y
        CEXR_CompressionMethod compression);

    void CEXR_Header_delete(
        CEXR_Header *header);

    void CEXR_Header_insert_channel(
        CEXR_Header *header,
        const char name[],
        const CEXR_Channel channel);

    int CEXR_Header_channel_exists(
        CEXR_Header *header,
        const char name[]);

    CEXR_Channel CEXR_Header_get_channel(
        CEXR_Header *header,
        const char name[]);

    CEXR_ChannelIterator CEXR_Header_new_channel_iterator(
        CEXR_Header *header);
};

CEXR_Header CEXR_Header_new(
    int display_window_min_x,
    int display_window_min_y,
    int display_window_max_x,
    int display_window_max_y,
    int data_window_min_x,
    int data_window_min_y,
    int data_window_max_x,
    int data_window_max_y,
    float pixel_aspect_ratio,
    float screen_window_center_x,
    float screen_window_center_y,
    float screen_window_width,
    int line_order,
    int compression
) {
    CEXR_Header header;

    header.header = new Header(
        Box2i(V2i(display_window_min_x, display_window_min_y), V2i(display_window_max_x, display_window_max_y)),
        Box2i(V2i(data_window_min_x, data_window_min_y), V2i(data_window_max_x, data_window_max_y)),
        pixel_aspect_ratio,
        V2f(screen_window_center_x, screen_window_center_y),
        screen_window_width,
        static_cast<LineOrder>(line_order),
        static_cast<Compression>(compression));
    return header;
}

void CEXR_Header_delete(CEXR_Header *header) {
    auto h = reinterpret_cast<Header*>(header->header);
    delete h;
}

void CEXR_Header_insert_channel(CEXR_Header *header, const char name[], const CEXR_Channel channel) {
    auto h = reinterpret_cast<Header*>(header->header);
    h->channels().insert(
        name,
        Channel(
            static_cast<PixelType>(channel.type),
            channel.x_sampling,
            channel.y_sampling,
            channel.p_linear));
}

int CEXR_Header_channel_exists(CEXR_Header *header, const char name[]) {
    auto h = reinterpret_cast<Header*>(header->header);
    h->channels().findChannel(name) != 0;
}

CEXR_Channel CEXR_Header_get_channel(CEXR_Header *header, const char name[]) {
    auto h = reinterpret_cast<Header*>(header->header);
    auto chan = h->channels().findChannel(name);

    CEXR_Channel channel;
    channel.type = chan->type;
    channel.x_sampling = chan->xSampling;
    channel.y_sampling = chan->ySampling;
    channel.p_linear = chan->pLinear;

    return channel;
}

CEXR_ChannelIterator CEXR_Header_new_channel_iterator(CEXR_Header *header) {
    auto h = reinterpret_cast<Header*>(header->header);

    CEXR_ChannelIterator channel_iter;
    channel_iter.begin = reinterpret_cast<void*>(new auto(h->channels().begin()));
    channel_iter.end = reinterpret_cast<void*>(new auto(h->channels().end()));

    return channel_iter;
}

//------------------------------------------------------------------------------
// FrameBuffer
extern "C" {
    struct CEXR_FrameBuffer {
        void *frame_buffer;
    };

    CEXR_FrameBuffer CEXR_FrameBuffer_new();

    void CEXR_FrameBuffer_delete(
        CEXR_FrameBuffer *frame_buffer);

    void CEXR_FrameBuffer_insert_slice(
        CEXR_FrameBuffer *frame_buffer,
        const char name[],
        char *base,
        size_t x_stride,
        size_t y_stride,
        int x_sampling,
        int y_sampling,
        double fill_value,
        int x_tile_coords, // bool
        int y_tile_coords // bool
        );
};

CEXR_FrameBuffer CEXR_FrameBuffer_new() {
    CEXR_FrameBuffer buffer;

    buffer.frame_buffer = reinterpret_cast<void*>(new FrameBuffer());

    return buffer;
}

void CEXR_FrameBuffer_delete(CEXR_FrameBuffer *frame_buffer) {
    auto buffer = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);
    delete buffer;
}

void CEXR_FrameBuffer_insert_slice(
    CEXR_FrameBuffer *frame_buffer,
    const char name[],
    CEXR_PixelType type,
    char *base,
    size_t x_stride,
    size_t y_stride,
    int x_sampling,
    int y_sampling,
    double fill_value,
    int x_tile_coords, // bool
    int y_tile_coords // bool
) {
    auto buffer = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);

    Slice slice;
    slice.type = static_cast<PixelType>(type);
    slice.base = base;
    slice.xStride = x_stride;
    slice.yStride = y_stride;
    slice.xSampling = x_sampling;
    slice.ySampling = y_sampling;
    slice.fillValue = fill_value;
    slice.xTileCoords = x_tile_coords;
    slice.yTileCoords = y_tile_coords;

    buffer->insert(name, slice);
}

//------------------------------------------------------------------------------
// OutputFile
extern "C" {
    struct CEXR_OutputFile {
        void *output_file;
    };

    CEXR_OutputFile CEXR_OutputFile_new(
        const char * file_name,
        const CEXR_Header *header,
        int num_threads);

    void CEXR_OutputFile_delete(
        CEXR_OutputFile *output_file);

    void CEXR_OutputFile_set_frame_buffer(
        CEXR_OutputFile* output_file,
        CEXR_FrameBuffer* frame_buffer);

    void CEXR_OutputFile_write_pixels(
        CEXR_OutputFile* output_file,
        int num_scan_lines);
};

CEXR_OutputFile CEXR_OutputFile_new(const char * file_name, const CEXR_Header *header, int num_threads) {
    CEXR_OutputFile output_file;

    output_file.output_file = reinterpret_cast<void*>(new OutputFile(
        file_name,
        *reinterpret_cast<Header*>(header->header),
        num_threads
    ));

    return output_file;
}

void CEXR_OutputFile_delete(CEXR_OutputFile *output_file) {
    auto outfile = reinterpret_cast<OutputFile*>(output_file->output_file);

    delete outfile;
}

void CEXR_OutputFile_set_frame_buffer(CEXR_OutputFile* output_file, CEXR_FrameBuffer* frame_buffer) {
    auto outfile = reinterpret_cast<OutputFile*>(output_file->output_file);
    auto framebuf = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);

    outfile->setFrameBuffer(*framebuf);
}

void CEXR_OutputFile_write_pixels(CEXR_OutputFile* output_file, int num_scan_lines) {
    auto outfile = reinterpret_cast<OutputFile*>(output_file->output_file);

    outfile->writePixels(num_scan_lines);
}

//------------------------------------------------------------------------------
// InputFile
extern "C" {
    struct CEXR_InputFile {
        CEXR_Header header;
        void *input_file;
    };

    CEXR_InputFile CEXR_InputFile_new(
        const char file_name[],
        int num_threads);

    void CEXR_InputFile_delete(
        CEXR_InputFile *input_file);

    const CEXR_Header *CEXR_InputFile_header(
        const CEXR_InputFile *input_file);

    int CEXR_InputFile_version(
        const CEXR_InputFile *input_file);

    void CEXR_InputFile_set_frame_buffer(
        CEXR_InputFile* input_file,
        CEXR_FrameBuffer* frame_buffer);

    int CEXR_InputFile_is_complete(
        const CEXR_InputFile *input_file);

    void CEXR_InputFile_read_pixels(
        CEXR_InputFile *input_file,
        int scanline_1,
        int scanline_2);
};

CEXR_InputFile CEXR_InputFile_new(const char file_name[], int num_threads) {
    CEXR_InputFile input_file;
    auto in_file = new InputFile(file_name, num_threads);
    input_file.header.header = const_cast<void*>(reinterpret_cast<const void*>(&in_file->header()));
    input_file.input_file = reinterpret_cast<void*>(in_file);

    return input_file;
}

void CEXR_InputFile_delete(CEXR_InputFile *input_file) {
    auto in_file = reinterpret_cast<InputFile*>(input_file->input_file);
    delete in_file;
}

const CEXR_Header *CEXR_InputFile_header(const CEXR_InputFile *input_file) {
    return &(input_file->header);
}

int CEXR_InputFile_version(const CEXR_InputFile *input_file) {
    auto in_file = reinterpret_cast<InputFile*>(input_file->input_file);
    return in_file->version();
}

void CEXR_InputFile_set_frame_buffer(CEXR_InputFile* input_file, CEXR_FrameBuffer* frame_buffer) {
    auto in_file = reinterpret_cast<InputFile*>(input_file->input_file);
    auto framebuf = reinterpret_cast<FrameBuffer*>(frame_buffer->frame_buffer);

    in_file->setFrameBuffer(*framebuf);
}

int CEXR_InputFile_is_complete(const CEXR_InputFile *input_file) {
    auto in_file = reinterpret_cast<InputFile*>(input_file->input_file);
    in_file->isComplete();
}

void CEXR_InputFile_read_pixels(CEXR_InputFile *input_file, int scanline_1, int scanline_2) {
    auto in_file = reinterpret_cast<InputFile*>(input_file->input_file);
    in_file->readPixels(scanline_1, scanline_2);
}
<|endoftext|>


<commit_before>#include <errno.h>
#include <nan.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "spidevice.h"
#include "transfer.h"
#include "util.h"

#include <unistd.h>

// TODO
// - Make sure it works when the messages array is empty

static int Transfer(
  int fd,
  spi_ioc_transfer *messages,
  uint32_t messageCount) {
  return ioctl(fd, SPI_IOC_MESSAGE(messageCount), messages);
}

class TransferWorker : public SpiAsyncWorker {
public:
  TransferWorker(
    Nan::Callback *callback,
    int fd,
    v8::Local<v8::Value> messages,
    spi_ioc_transfer *spiMessages,
    uint32_t messageCount
  ) : SpiAsyncWorker(callback),
    fd_(fd),
    spiMessages_(spiMessages),
    messageCount_(messageCount) {
    SaveToPersistent("messages", messages);
  }

  ~TransferWorker() {
  }

  void Execute() {
    int ret = Transfer(fd_, spiMessages_, messageCount_);
    free(spiMessages_);
    if (ret == -1) {
      SetErrorNo(errno);
      SetErrorSyscall("transfer");
    }
  }

  void HandleOKCallback() {
    Nan::HandleScope scope;

    v8::Local<v8::Value> messages = GetFromPersistent("messages");

    v8::Local<v8::Value> argv[] = {
      Nan::Null(),
      messages
    };

    callback->Call(2, argv);
  }

private:
  int fd_;
  spi_ioc_transfer *spiMessages_;
  uint32_t messageCount_;
};

static int32_t ToSpiMessages(
  v8::Local<v8::Array> messages,
  spi_ioc_transfer *spiMessages
) {
  for (unsigned i = 0; i < messages->Length(); ++i) {
    // Message

    v8::Local<v8::Value> message = messages->Get(i);

    if (!message->IsObject()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "each message being transfered should be an object"));
      return -1;
    }

    v8::Local<v8::Object> msg = v8::Local<v8::Object>::Cast(message);

    // byteLength

    v8::Local<v8::Value> byteLength = Nan::Get(msg,
      Nan::New<v8::String>("byteLength").ToLocalChecked()).ToLocalChecked();

    if (byteLength->IsUndefined()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message byteLength not specified"));
      return -1;
    } else if (!byteLength->IsUint32()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message byteLength should be an unsigned integer"));
      return -1;
    }

    uint32_t length = byteLength->Uint32Value();
    spiMessages[i].len = length;

    // sendBuffer

    v8::Local<v8::Value> sendBuffer = Nan::Get(msg,
      Nan::New<v8::String>("sendBuffer").ToLocalChecked()).ToLocalChecked();

    if (sendBuffer->IsNull() || sendBuffer->IsUndefined()) {
      // No sendBuffer so tx_buf should be NULL. This is already the case.
    } else if (node::Buffer::HasInstance(sendBuffer)) {
      if (node::Buffer::Length(sendBuffer) < length) {
        Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
          "message sendBuffer contains less than byteLength bytes"));
        return -1;
      }
      spiMessages[i].tx_buf = (__u64) node::Buffer::Data(sendBuffer);
    } else {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message sendBuffer should be null, undefined, or a Buffer object"));
      return -1;
    }

    // receiveBuffer

    v8::Local<v8::Value> receiveBuffer = Nan::Get(msg,
      Nan::New<v8::String>("receiveBuffer").ToLocalChecked()).ToLocalChecked();

    if (receiveBuffer->IsNull() || receiveBuffer->IsUndefined()) {
      // No receiveBuffer so rx_buf should be NULL. This is already the case.
    } else if (node::Buffer::HasInstance(receiveBuffer)) {
      if (node::Buffer::Length(receiveBuffer) < length) {
        Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
          "message receiveBuffer contains less than byteLength bytes"));
        return -1;
      }
      spiMessages[i].rx_buf = (__u64) node::Buffer::Data(receiveBuffer);
    } else {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message receiveBuffer should be null, undefined, or a Buffer object"));
      return -1;
    }

    // sendBuffer and receiveBuffer

    if ((sendBuffer->IsNull() || sendBuffer->IsUndefined()) &&
        (receiveBuffer->IsNull() || receiveBuffer->IsUndefined())) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message contains neither a sendBuffer nor a receiveBuffer"));
      return -1;
    }

    // speed

    v8::Local<v8::Value> speed = Nan::Get(msg,
      Nan::New<v8::String>("speed").ToLocalChecked()).ToLocalChecked();

    if (speed->IsUndefined()) {
      // No speed defined, nothing to do.
    } else if (!speed->IsUint32()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message speed should be an unsigned integer"));
      return -1;
    } else {
      spiMessages[i].speed_hz = speed->Uint32Value();
    }

    // chipSelectChange

    v8::Local<v8::Value> chipSelectChange = Nan::Get(msg,
      Nan::New<v8::String>("chipSelectChange").ToLocalChecked()).
      ToLocalChecked();

    if (chipSelectChange->IsUndefined()) {
      // No chipSelectChange defined, nothing to do.
    } else if (!chipSelectChange->IsBoolean()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message chipSelectChange should be a boolean"));
      return -1;
    } else {
      spiMessages[i].cs_change = chipSelectChange->BooleanValue() ? 1 : 0;
    }
  }

  return 0;
}

void Transfer(Nan::NAN_METHOD_ARGS_TYPE info) {
  SpiDevice *device = Nan::ObjectWrap::Unwrap<SpiDevice>(info.This());
  int fd = device->Fd();

  if (fd == -1) {
    return Nan::ThrowError(Nan::ErrnoException(EPERM, "transfer",
      "device closed, operation not permitted"));
  }

  if (info.Length() < 2 ||
      !info[0]->IsArray() ||
      !info[1]->IsFunction()) {
    return Nan::ThrowError(Nan::ErrnoException(EINVAL, "transfer",
      "incorrect arguments passed to transfer(messages, cb)"));
  }

  v8::Local<v8::Array> messages = info[0].As<v8::Array>();
  Nan::Callback *callback = new Nan::Callback(info[1].As<v8::Function>());

  spi_ioc_transfer *spiMessages = (spi_ioc_transfer *)
    malloc(messages->Length() * sizeof(spi_ioc_transfer));
  memset(spiMessages, 0, messages->Length() * sizeof(spi_ioc_transfer));

  if (ToSpiMessages(messages, spiMessages) == -1) {
    free(spiMessages);
    return;
  }

  Nan::AsyncQueueWorker(new TransferWorker(
    callback,
    fd,
    messages,
    spiMessages,
    messages->Length()
  ));

  info.GetReturnValue().Set(info.This());
}

void TransferSync(Nan::NAN_METHOD_ARGS_TYPE info) {
  SpiDevice *device = Nan::ObjectWrap::Unwrap<SpiDevice>(info.This());
  int fd = device->Fd();

  if (fd == -1) {
    return Nan::ThrowError(Nan::ErrnoException(EPERM, "transferSync",
      "device closed, operation not permitted"));
  }

  if (info.Length() < 1 || !info[0]->IsArray()) {
    return Nan::ThrowError(Nan::ErrnoException(EINVAL, "transfer",
      "incorrect arguments passed to transferSync(messages)"));
  }

  v8::Local<v8::Array> messages = info[0].As<v8::Array>();

  spi_ioc_transfer *spiMessages = (spi_ioc_transfer *)
    malloc(messages->Length() * sizeof(spi_ioc_transfer));
  memset(spiMessages, 0, messages->Length() * sizeof(spi_ioc_transfer));

  if (ToSpiMessages(messages, spiMessages) == 0) {
    if (Transfer(fd, spiMessages, messages->Length()) == -1) {
      Nan::ThrowError(Nan::ErrnoException(errno, "transferSync", ""));
    }
  }

  free(spiMessages);

  info.GetReturnValue().Set(info.This());
}

<commit_msg>stray include removed<commit_after>#include <errno.h>
#include <nan.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "spidevice.h"
#include "transfer.h"
#include "util.h"

// TODO
// - Make sure it works when the messages array is empty

static int Transfer(
  int fd,
  spi_ioc_transfer *messages,
  uint32_t messageCount) {
  return ioctl(fd, SPI_IOC_MESSAGE(messageCount), messages);
}

class TransferWorker : public SpiAsyncWorker {
public:
  TransferWorker(
    Nan::Callback *callback,
    int fd,
    v8::Local<v8::Value> messages,
    spi_ioc_transfer *spiMessages,
    uint32_t messageCount
  ) : SpiAsyncWorker(callback),
    fd_(fd),
    spiMessages_(spiMessages),
    messageCount_(messageCount) {
    SaveToPersistent("messages", messages);
  }

  ~TransferWorker() {
  }

  void Execute() {
    int ret = Transfer(fd_, spiMessages_, messageCount_);
    free(spiMessages_);
    if (ret == -1) {
      SetErrorNo(errno);
      SetErrorSyscall("transfer");
    }
  }

  void HandleOKCallback() {
    Nan::HandleScope scope;

    v8::Local<v8::Value> messages = GetFromPersistent("messages");

    v8::Local<v8::Value> argv[] = {
      Nan::Null(),
      messages
    };

    callback->Call(2, argv);
  }

private:
  int fd_;
  spi_ioc_transfer *spiMessages_;
  uint32_t messageCount_;
};

static int32_t ToSpiMessages(
  v8::Local<v8::Array> messages,
  spi_ioc_transfer *spiMessages
) {
  for (unsigned i = 0; i < messages->Length(); ++i) {
    // Message

    v8::Local<v8::Value> message = messages->Get(i);

    if (!message->IsObject()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "each message being transfered should be an object"));
      return -1;
    }

    v8::Local<v8::Object> msg = v8::Local<v8::Object>::Cast(message);

    // byteLength

    v8::Local<v8::Value> byteLength = Nan::Get(msg,
      Nan::New<v8::String>("byteLength").ToLocalChecked()).ToLocalChecked();

    if (byteLength->IsUndefined()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message byteLength not specified"));
      return -1;
    } else if (!byteLength->IsUint32()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message byteLength should be an unsigned integer"));
      return -1;
    }

    uint32_t length = byteLength->Uint32Value();
    spiMessages[i].len = length;

    // sendBuffer

    v8::Local<v8::Value> sendBuffer = Nan::Get(msg,
      Nan::New<v8::String>("sendBuffer").ToLocalChecked()).ToLocalChecked();

    if (sendBuffer->IsNull() || sendBuffer->IsUndefined()) {
      // No sendBuffer so tx_buf should be NULL. This is already the case.
    } else if (node::Buffer::HasInstance(sendBuffer)) {
      if (node::Buffer::Length(sendBuffer) < length) {
        Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
          "message sendBuffer contains less than byteLength bytes"));
        return -1;
      }
      spiMessages[i].tx_buf = (__u64) node::Buffer::Data(sendBuffer);
    } else {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message sendBuffer should be null, undefined, or a Buffer object"));
      return -1;
    }

    // receiveBuffer

    v8::Local<v8::Value> receiveBuffer = Nan::Get(msg,
      Nan::New<v8::String>("receiveBuffer").ToLocalChecked()).ToLocalChecked();

    if (receiveBuffer->IsNull() || receiveBuffer->IsUndefined()) {
      // No receiveBuffer so rx_buf should be NULL. This is already the case.
    } else if (node::Buffer::HasInstance(receiveBuffer)) {
      if (node::Buffer::Length(receiveBuffer) < length) {
        Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
          "message receiveBuffer contains less than byteLength bytes"));
        return -1;
      }
      spiMessages[i].rx_buf = (__u64) node::Buffer::Data(receiveBuffer);
    } else {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message receiveBuffer should be null, undefined, or a Buffer object"));
      return -1;
    }

    // sendBuffer and receiveBuffer

    if ((sendBuffer->IsNull() || sendBuffer->IsUndefined()) &&
        (receiveBuffer->IsNull() || receiveBuffer->IsUndefined())) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message contains neither a sendBuffer nor a receiveBuffer"));
      return -1;
    }

    // speed

    v8::Local<v8::Value> speed = Nan::Get(msg,
      Nan::New<v8::String>("speed").ToLocalChecked()).ToLocalChecked();

    if (speed->IsUndefined()) {
      // No speed defined, nothing to do.
    } else if (!speed->IsUint32()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message speed should be an unsigned integer"));
      return -1;
    } else {
      spiMessages[i].speed_hz = speed->Uint32Value();
    }

    // chipSelectChange

    v8::Local<v8::Value> chipSelectChange = Nan::Get(msg,
      Nan::New<v8::String>("chipSelectChange").ToLocalChecked()).
      ToLocalChecked();

    if (chipSelectChange->IsUndefined()) {
      // No chipSelectChange defined, nothing to do.
    } else if (!chipSelectChange->IsBoolean()) {
      Nan::ThrowError(Nan::ErrnoException(EINVAL, "toSpiMessages",
        "message chipSelectChange should be a boolean"));
      return -1;
    } else {
      spiMessages[i].cs_change = chipSelectChange->BooleanValue() ? 1 : 0;
    }
  }

  return 0;
}

void Transfer(Nan::NAN_METHOD_ARGS_TYPE info) {
  SpiDevice *device = Nan::ObjectWrap::Unwrap<SpiDevice>(info.This());
  int fd = device->Fd();

  if (fd == -1) {
    return Nan::ThrowError(Nan::ErrnoException(EPERM, "transfer",
      "device closed, operation not permitted"));
  }

  if (info.Length() < 2 ||
      !info[0]->IsArray() ||
      !info[1]->IsFunction()) {
    return Nan::ThrowError(Nan::ErrnoException(EINVAL, "transfer",
      "incorrect arguments passed to transfer(messages, cb)"));
  }

  v8::Local<v8::Array> messages = info[0].As<v8::Array>();
  Nan::Callback *callback = new Nan::Callback(info[1].As<v8::Function>());

  spi_ioc_transfer *spiMessages = (spi_ioc_transfer *)
    malloc(messages->Length() * sizeof(spi_ioc_transfer));
  memset(spiMessages, 0, messages->Length() * sizeof(spi_ioc_transfer));

  if (ToSpiMessages(messages, spiMessages) == -1) {
    free(spiMessages);
    return;
  }

  Nan::AsyncQueueWorker(new TransferWorker(
    callback,
    fd,
    messages,
    spiMessages,
    messages->Length()
  ));

  info.GetReturnValue().Set(info.This());
}

void TransferSync(Nan::NAN_METHOD_ARGS_TYPE info) {
  SpiDevice *device = Nan::ObjectWrap::Unwrap<SpiDevice>(info.This());
  int fd = device->Fd();

  if (fd == -1) {
    return Nan::ThrowError(Nan::ErrnoException(EPERM, "transferSync",
      "device closed, operation not permitted"));
  }

  if (info.Length() < 1 || !info[0]->IsArray()) {
    return Nan::ThrowError(Nan::ErrnoException(EINVAL, "transfer",
      "incorrect arguments passed to transferSync(messages)"));
  }

  v8::Local<v8::Array> messages = info[0].As<v8::Array>();

  spi_ioc_transfer *spiMessages = (spi_ioc_transfer *)
    malloc(messages->Length() * sizeof(spi_ioc_transfer));
  memset(spiMessages, 0, messages->Length() * sizeof(spi_ioc_transfer));

  if (ToSpiMessages(messages, spiMessages) == 0) {
    if (Transfer(fd, spiMessages, messages->Length()) == -1) {
      Nan::ThrowError(Nan::ErrnoException(errno, "transferSync", ""));
    }
  }

  free(spiMessages);

  info.GetReturnValue().Set(info.This());
}

<|endoftext|>


<commit_before>// This file is part of Tasks.
//
// Tasks 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, either version 3 of the License, or
// (at your option) any later version.
//
// Tasks is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tasks.  If not, see <http://www.gnu.org/licenses/>.

// includes
// std
#include <fstream>
#include <iostream>
#include <tuple>

// boost
#define BOOST_TEST_MODULE QPMultiRobotTest
#include <boost/test/unit_test.hpp>
#include <boost/math/constants/constants.hpp>

// RBDyn
#include <RBDyn/EulerIntegration.h>
#include <RBDyn/FK.h>
#include <RBDyn/FV.h>
#include <RBDyn/ID.h>
#include <RBDyn/MultiBody.h>
#include <RBDyn/MultiBodyConfig.h>
#include <RBDyn/MultiBodyGraph.h>

// Tasks
#include "Bounds.h"
#include "QPConstr.h"
#include "QPMotionConstr.h"
#include "QPSolver.h"
#include "QPTasks.h"

// Arms
#include "arms.h"

// Test contact between two robot.
// We set two identical robot at the same positio
// then we link the end effector and add a task
// to make it move on the second robot.
// The first robot must have the same motion.
BOOST_AUTO_TEST_CASE(TwoArmContactTest)
{
	using namespace Eigen;
	using namespace sva;
	using namespace rbd;
	using namespace tasks;
	namespace cst = boost::math::constants;

	MultiBody mb1, mb2;
	MultiBodyConfig mbc1Init, mbc2Init;

	std::tie(mb1, mbc1Init) = makeZXZArm();
	std::tie(mb2, mbc2Init) = makeZXZArm();

	forwardKinematics(mb1, mbc1Init);
	forwardVelocity(mb1, mbc1Init);
	forwardKinematics(mb2, mbc2Init);
	forwardVelocity(mb2, mbc2Init);

	sva::PTransformd X_0_b1(mbc1Init.bodyPosW.back());
	sva::PTransformd X_0_b2(mbc2Init.bodyPosW.back());
	sva::PTransformd X_b1_b2(X_0_b2*X_0_b1.inv());

	std::vector<MultiBody> mbs = {mb1, mb2};
	std::vector<MultiBodyConfig> mbcs = {mbc1Init, mbc2Init};

	// Test ContactAccConstr constraint
	// Also test PositionTask on the second robot

	qp::QPSolver solver;

	std::vector<qp::UnilateralContact> contVec =
		{qp::UnilateralContact(0, 1, 3, 3,
			{Vector3d::Zero()}, RotX(cst::pi<double>()/2.), X_b1_b2,
			3, std::tan(cst::pi<double>()/4.))};

	Matrix3d oriD = RotZ(cst::pi<double>()/4.);
	Vector3d posD(oriD*mbc2Init.bodyPosW.back().translation());
	qp::PositionTask posTask(mbs, 1, 3, posD);
	qp::SetPointTask posTaskSp(mbs, 1, &posTask, 1000., 1.);

	qp::ContactAccConstr contCstrAcc;

	contCstrAcc.addToSolver(solver);
	solver.addTask(&posTaskSp);

	solver.nrVars(mbs, contVec, {});
	solver.updateConstrSize();

	// 3 dof + 3 dof + 3 lambda
	BOOST_CHECK_EQUAL(solver.nrVars(), 3 + 3 + 3);

	for(int i = 0; i < 1000; ++i)
	{
		BOOST_REQUIRE(solver.solve(mbs, mbcs));
		for(std::size_t r = 0; r < mbs.size(); ++r)
		{
			eulerIntegration(mbs[r], mbcs[r], 0.001);

			forwardKinematics(mbs[r], mbcs[r]);
			forwardVelocity(mbs[r], mbcs[r]);
		}
		// check that the link hold
		sva::PTransformd X_0_b1_post(mbcs[0].bodyPosW.back());
		sva::PTransformd X_0_b2_post(mbcs[1].bodyPosW.back());
		sva::PTransformd X_b1_b2_post(X_0_b2*X_0_b1.inv());
		BOOST_CHECK_SMALL((X_b1_b2.matrix() - X_b1_b2_post.matrix()).norm(), 1e-5);
	}
	// check that the task is well minimized
	BOOST_CHECK_SMALL(posTask.eval().norm(), 1e-5);

	contCstrAcc.removeFromSolver(solver);
	solver.removeTask(&posTaskSp);

	// Test ContactSpeedConstr constraint
	// Also test OrientationTask on the second robot

	mbcs = {mbc1Init, mbc2Init};
	qp::OrientationTask oriTask(mbs, 1, 3, oriD);
	qp::SetPointTask oriTaskSp(mbs, 1, &oriTask, 1000., 1.);

	qp::ContactSpeedConstr contCstrSpeed(0.001);

	contCstrSpeed.addToSolver(solver);
	solver.addTask(&oriTaskSp);

	solver.nrVars(mbs, contVec, {});
	solver.updateConstrSize();

	for(int i = 0; i < 1000; ++i)
	{
		BOOST_REQUIRE(solver.solve(mbs, mbcs));
		for(std::size_t r = 0; r < mbs.size(); ++r)
		{
			eulerIntegration(mbs[r], mbcs[r], 0.001);

			forwardKinematics(mbs[r], mbcs[r]);
			forwardVelocity(mbs[r], mbcs[r]);
		}
		// check that the link hold
		sva::PTransformd X_0_b1_post(mbcs[0].bodyPosW.back());
		sva::PTransformd X_0_b2_post(mbcs[1].bodyPosW.back());
		sva::PTransformd X_b1_b2_post(X_0_b2*X_0_b1.inv());
		BOOST_CHECK_SMALL((X_b1_b2.matrix() - X_b1_b2_post.matrix()).norm(), 1e-5);
	}
	// check that the task is well minimized
	BOOST_CHECK_SMALL(oriTask.eval().norm(), 1e-5);
}
<commit_msg>Document a little TwoArmDDynamicContactTest.<commit_after>// This file is part of Tasks.
//
// Tasks 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, either version 3 of the License, or
// (at your option) any later version.
//
// Tasks is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tasks.  If not, see <http://www.gnu.org/licenses/>.

// includes
// std
#include <fstream>
#include <iostream>
#include <tuple>

// boost
#define BOOST_TEST_MODULE QPMultiRobotTest
#include <boost/test/unit_test.hpp>
#include <boost/math/constants/constants.hpp>

// RBDyn
#include <RBDyn/EulerIntegration.h>
#include <RBDyn/FK.h>
#include <RBDyn/FV.h>
#include <RBDyn/ID.h>
#include <RBDyn/MultiBody.h>
#include <RBDyn/MultiBodyConfig.h>
#include <RBDyn/MultiBodyGraph.h>

// Tasks
#include "Bounds.h"
#include "QPConstr.h"
#include "QPMotionConstr.h"
#include "QPSolver.h"
#include "QPTasks.h"

// Arms
#include "arms.h"

// Test contact between two robot.
// We set two identical robot at the same positio
// then we link the end effector and add a task
// to make it move on the second robot.
// The first robot must have the same motion.
BOOST_AUTO_TEST_CASE(TwoArmContactTest)
{
	using namespace Eigen;
	using namespace sva;
	using namespace rbd;
	using namespace tasks;
	namespace cst = boost::math::constants;

	MultiBody mb1, mb2;
	MultiBodyConfig mbc1Init, mbc2Init;

	std::tie(mb1, mbc1Init) = makeZXZArm();
	std::tie(mb2, mbc2Init) = makeZXZArm();

	forwardKinematics(mb1, mbc1Init);
	forwardVelocity(mb1, mbc1Init);
	forwardKinematics(mb2, mbc2Init);
	forwardVelocity(mb2, mbc2Init);

	sva::PTransformd X_0_b1(mbc1Init.bodyPosW.back());
	sva::PTransformd X_0_b2(mbc2Init.bodyPosW.back());
	sva::PTransformd X_b1_b2(X_0_b2*X_0_b1.inv());

	std::vector<MultiBody> mbs = {mb1, mb2};
	std::vector<MultiBodyConfig> mbcs = {mbc1Init, mbc2Init};

	// Test ContactAccConstr constraint
	// Also test PositionTask on the second robot

	qp::QPSolver solver;

	std::vector<qp::UnilateralContact> contVec =
		{qp::UnilateralContact(0, 1, 3, 3,
			{Vector3d::Zero()}, RotX(cst::pi<double>()/2.), X_b1_b2,
			3, std::tan(cst::pi<double>()/4.))};

	Matrix3d oriD = RotZ(cst::pi<double>()/4.);
	Vector3d posD(oriD*mbc2Init.bodyPosW.back().translation());
	qp::PositionTask posTask(mbs, 1, 3, posD);
	qp::SetPointTask posTaskSp(mbs, 1, &posTask, 1000., 1.);

	qp::ContactAccConstr contCstrAcc;

	contCstrAcc.addToSolver(solver);
	solver.addTask(&posTaskSp);

	solver.nrVars(mbs, contVec, {});
	solver.updateConstrSize();

	// 3 dof + 3 dof + 3 lambda
	BOOST_CHECK_EQUAL(solver.nrVars(), 3 + 3 + 3);

	for(int i = 0; i < 1000; ++i)
	{
		BOOST_REQUIRE(solver.solve(mbs, mbcs));
		for(std::size_t r = 0; r < mbs.size(); ++r)
		{
			eulerIntegration(mbs[r], mbcs[r], 0.001);

			forwardKinematics(mbs[r], mbcs[r]);
			forwardVelocity(mbs[r], mbcs[r]);
		}
		// check that the link hold
		sva::PTransformd X_0_b1_post(mbcs[0].bodyPosW.back());
		sva::PTransformd X_0_b2_post(mbcs[1].bodyPosW.back());
		sva::PTransformd X_b1_b2_post(X_0_b2*X_0_b1.inv());
		BOOST_CHECK_SMALL((X_b1_b2.matrix() - X_b1_b2_post.matrix()).norm(), 1e-5);
	}
	// check that the task is well minimized
	BOOST_CHECK_SMALL(posTask.eval().norm(), 1e-5);

	contCstrAcc.removeFromSolver(solver);
	solver.removeTask(&posTaskSp);

	// Test ContactSpeedConstr constraint
	// Also test OrientationTask on the second robot

	mbcs = {mbc1Init, mbc2Init};
	qp::OrientationTask oriTask(mbs, 1, 3, oriD);
	qp::SetPointTask oriTaskSp(mbs, 1, &oriTask, 1000., 1.);

	qp::ContactSpeedConstr contCstrSpeed(0.001);

	contCstrSpeed.addToSolver(solver);
	solver.addTask(&oriTaskSp);

	solver.nrVars(mbs, contVec, {});
	solver.updateConstrSize();

	for(int i = 0; i < 1000; ++i)
	{
		BOOST_REQUIRE(solver.solve(mbs, mbcs));
		for(std::size_t r = 0; r < mbs.size(); ++r)
		{
			eulerIntegration(mbs[r], mbcs[r], 0.001);

			forwardKinematics(mbs[r], mbcs[r]);
			forwardVelocity(mbs[r], mbcs[r]);
		}
		// check that the link hold
		sva::PTransformd X_0_b1_post(mbcs[0].bodyPosW.back());
		sva::PTransformd X_0_b2_post(mbcs[1].bodyPosW.back());
		sva::PTransformd X_b1_b2_post(X_0_b2*X_0_b1.inv());
		BOOST_CHECK_SMALL((X_b1_b2.matrix() - X_b1_b2_post.matrix()).norm(), 1e-5);
	}
	// check that the task is well minimized
	BOOST_CHECK_SMALL(oriTask.eval().norm(), 1e-5);
}

// Test Motion constraint
// We setup two arm, one with a fixed base and the second
// with a freebase put on the body b3 of the first robot.
// First we launch an impossible motion to check the dynamics
// After we try with an unilateral contact
// Then we try with a bilateral contact.
BOOST_AUTO_TEST_CASE(TwoArmDDynamicContactTest)
{
	using namespace Eigen;
	using namespace sva;
	using namespace rbd;
	using namespace tasks;
	namespace cst = boost::math::constants;

	MultiBody mb1, mb2;
	MultiBodyConfig mbc1Init, mbc2Init;

	std::tie(mb1, mbc1Init) = makeZXZArm();

	forwardKinematics(mb1, mbc1Init);
	forwardVelocity(mb1, mbc1Init);

	std::tie(mb2, mbc2Init) = makeZXZArm(false);
	Vector3d mb2InitPos = mbc1Init.bodyPosW.back().translation();
	Quaterniond mb2InitOri(RotY(cst::pi<double>()/2.));
	mbc2Init.q[0] = {mb2InitOri.w(), mb2InitOri.x(), mb2InitOri.y(), mb2InitOri.z(),
		mb2InitPos.x(), mb2InitPos.y()+ 1, mb2InitPos.z()};
	forwardKinematics(mb2, mbc2Init);
	forwardVelocity(mb2, mbc2Init);

	sva::PTransformd X_0_b1(mbc1Init.bodyPosW.back());
	sva::PTransformd X_0_b2(mbc2Init.bodyPosW.front());
	sva::PTransformd X_b1_b2(X_0_b2*X_0_b1.inv());

	std::vector<MultiBody> mbs = {mb1, mb2};
	std::vector<MultiBodyConfig> mbcs = {mbc1Init, mbc2Init};

	// Test ContactAccConstr constraint
	// Also test PositionTask on the second robot

	qp::QPSolver solver;

	std::vector<Eigen::Vector3d> points =
	{
		Vector3d(0.1, 0., 0.1),
		Vector3d(0.1, 0., -0.1),
		Vector3d(-0.1, 0., -0.1),
		Vector3d(-0.1, 0., 0.1),
	};

	std::vector<Eigen::Vector3d> biPoints =
	{
		Vector3d(0., 0., 0.),
		Vector3d(0., 0., 0.),
		Vector3d(0., 0., 0.),
		Vector3d(0., 0., 0.),
	};

	const int nrGen = 4;
	std::vector<Eigen::Matrix3d> biFrames =
	{
		RotX((1.*cst::pi<double>())/4.),
		RotX((3.*cst::pi<double>())/4.),
		Matrix3d(RotX((1.*cst::pi<double>())/4.)*RotY(cst::pi<double>()/2.)),
		Matrix3d(RotX((3.*cst::pi<double>())/4.)*RotY(cst::pi<double>()/2.)),
	};

	// The fixed robot can pull the other
	std::vector<qp::UnilateralContact> contVecFail =
		{qp::UnilateralContact(0, 1, 3, 0,
			points, RotX(-cst::pi<double>()/2.), X_b1_b2,
			nrGen, 0.7)};

	// The fixed robot can push the other
	std::vector<qp::UnilateralContact> contVec =
		{qp::UnilateralContact({0, 1, 3, 0},
			points, RotX(cst::pi<double>()/2.), X_b1_b2,
			nrGen, 0.7)};

	// The fixed robot has non coplanar force apply on the other
	std::vector<qp::BilateralContact> contVecBi =
		{qp::BilateralContact({0, 1, 3, 0},
			biPoints, biFrames, X_b1_b2,
			nrGen, 1.)};

	qp::PositionTask posTask(mbs, 0, 3, mbc1Init.bodyPosW.back().translation());
	qp::SetPointTask posTaskSp(mbs, 0, &posTask, 10., 10000.);
	qp::OrientationTask oriTask(mbs, 0, 3, mbc1Init.bodyPosW.back().rotation());
	qp::SetPointTask oriTaskSp(mbs, 0, &oriTask, 10., 10000.);
	qp::PostureTask posture1Task(mbs, 0, mbc1Init.q, 2., 1.);
	qp::PostureTask posture2Task(mbs, 1, mbc2Init.q, 2., 1.);

	qp::ContactSpeedConstr contCstrSpeed(0.001);

	const double Inf = std::numeric_limits<double>::infinity();
	std::vector<std::vector<double>> torqueMin1 = {{},{-Inf},{-Inf},{-Inf}};
	std::vector<std::vector<double>> torqueMax1 = {{},{Inf},{Inf},{Inf}};
	std::vector<std::vector<double>> torqueMin2 = {{0., 0., 0., 0., 0., 0.},
																							{-Inf},{-Inf},{-Inf}};
	std::vector<std::vector<double>> torqueMax2 = {{0., 0., 0., 0., 0., 0.},
																							{Inf},{Inf},{Inf}};
	qp::MotionConstr motion1(mbs, 0, {torqueMin1, torqueMax1});
	qp::MotionConstr motion2(mbs, 1, {torqueMin2, torqueMax2});
	qp::PositiveLambda plCstr;

	motion1.addToSolver(solver);
	motion2.addToSolver(solver);
	plCstr.addToSolver(solver);

	contCstrSpeed.addToSolver(solver);
	solver.addTask(&posTaskSp);
	solver.addTask(&oriTaskSp);
	solver.addTask(&posture1Task);
	solver.addTask(&posture2Task);

	// check the impossible motion
	solver.nrVars(mbs, contVecFail, {});
	solver.updateConstrSize();

	// 3 dof + 9 dof + 4*nrGen lambda
	BOOST_CHECK_EQUAL(solver.nrVars(), 3 + 9 + 4*nrGen);
	BOOST_REQUIRE(!solver.solve(mbs, mbcs));

	// check the unilateral motion
	mbcs = {mbc1Init, mbc2Init};
	solver.nrVars(mbs, contVec, {});
	solver.updateConstrSize();

	for(int i = 0; i < 1000; ++i)
	{
		BOOST_REQUIRE(solver.solve(mbs, mbcs));
		for(std::size_t r = 0; r < mbs.size(); ++r)
		{
			eulerIntegration(mbs[r], mbcs[r], 0.001);

			forwardKinematics(mbs[r], mbcs[r]);
			forwardVelocity(mbs[r], mbcs[r]);
		}
		// check that the link hold
		sva::PTransformd X_0_b1_post(mbcs[0].bodyPosW.back());
		sva::PTransformd X_0_b2_post(mbcs[1].bodyPosW.front());
		sva::PTransformd X_b1_b2_post(X_0_b2*X_0_b1.inv());
		BOOST_CHECK_SMALL((X_b1_b2.matrix() - X_b1_b2_post.matrix()).norm(), 1e-5);

		// force in world frame must be the same
		auto f1 = X_0_b1.rotation().transpose()*contVec[0].force(solver.lambdaVec(0), contVec[0].r1Cone);
		auto f2 = X_0_b2.rotation().transpose()*contVec[0].force(solver.lambdaVec(0), contVec[0].r2Cone);
		BOOST_CHECK_SMALL((f1 + f2).norm(), 1e-5);
	}

	// check the bilateral motion
	mbcs = {mbc1Init, mbc2Init};
	solver.nrVars(mbs, {}, contVecBi);
	solver.updateConstrSize();
	// 3 dof + 9 dof + 4*nrGen lambda
	BOOST_CHECK_EQUAL(solver.nrVars(), 3 + 9 + 4*nrGen);

	for(int i = 0; i < 1000; ++i)
	{
		//std::cout << i << std::endl;
		BOOST_REQUIRE(solver.solve(mbs, mbcs));
		for(std::size_t r = 0; r < mbs.size(); ++r)
		{
			eulerIntegration(mbs[r], mbcs[r], 0.001);

			forwardKinematics(mbs[r], mbcs[r]);
			forwardVelocity(mbs[r], mbcs[r]);
		}
		// check that the link hold
		sva::PTransformd X_0_b1_post(mbcs[0].bodyPosW.back());
		sva::PTransformd X_0_b2_post(mbcs[1].bodyPosW.front());
		sva::PTransformd X_b1_b2_post(X_0_b2*X_0_b1.inv());
		BOOST_CHECK_SMALL((X_b1_b2.matrix() - X_b1_b2_post.matrix()).norm(), 1e-5);

		// force in world frame must be the same
		auto f1 = X_0_b1.rotation().transpose()*contVec[0].force(solver.lambdaVec(0), contVec[0].r1Cone);
		auto f2 = X_0_b2.rotation().transpose()*contVec[0].force(solver.lambdaVec(0), contVec[0].r2Cone);
		BOOST_CHECK_SMALL((f1 + f2).norm(), 1e-5);
	}

	plCstr.removeFromSolver(solver);
	motion2.removeFromSolver(solver);
	motion1.removeFromSolver(solver);
	contCstrSpeed.removeFromSolver(solver);

	solver.removeTask(&posture1Task);
	solver.removeTask(&posture2Task);
	solver.removeTask(&posTaskSp);
	solver.removeTask(&oriTaskSp);
}
<|endoftext|>