<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//_________________________________________________________________________
//  Algorithm class for the reconstruction: clusterizer
//                                          track segment maker
//                                          particle identifier
//
//*-- Author: Gines Martinez & Yves Schutz (SUBATECH)

// --- ROOT system ---

#include "TClonesArray.h"

// --- Standard library ---

#include <iomanip>

// --- AliRoot header files ---

#include "AliPHOSReconstructioner.h"
#include "AliPHOSClusterizer.h"

ClassImp(AliPHOSReconstructioner)

//____________________________________________________________________________
AliPHOSReconstructioner::AliPHOSReconstructioner(AliPHOSClusterizer * Clusterizer,
						 AliPHOSTrackSegmentMaker * Tracker,
						 AliPHOSPID * Pid)
{
  // ctor

  fClusterizer        = Clusterizer ;
  fTrackSegmentMaker  = Tracker ;
  fPID                = Pid ;
  fDebugReconstruction = kFALSE ;
}

//____________________________________________________________________________
 void AliPHOSReconstructioner::Init(AliPHOSClusterizer * Clusterizer,
						 AliPHOSTrackSegmentMaker * Tracker,
						 AliPHOSPID * Pid)
{
  fClusterizer        = Clusterizer ;
  fTrackSegmentMaker  = Tracker ;
  fPID                = Pid ;
  fDebugReconstruction = kFALSE ;
}

//____________________________________________________________________________
 void AliPHOSReconstructioner::Make(DigitsList * dl, RecPointsList * emccl, RecPointsList * ppsdl,
				     TrackSegmentsList * trsl, RecParticlesList * rpl)
{
  // Launches the Reconstruction process in the sequence: Make the reconstructed poins (clusterize)
  //                                                      Make the track segments
  //                                                      Make the reconstructed particles

  Int_t index ;
  // Digit Debuging

  if  (fDebugReconstruction)
    {
      cout << ">>>>>>>>>>>>>>>>>>>>>> DebugReconstruction  <<<<<<<<<<<<<<<<<<<<<<<<<<"  << endl ;
      cout << "DebugReconstruction>>> Digit list entries is " <<    dl->GetEntries() << endl ;
      AliPHOSDigit * Digit;
      cout << "DebugReconstruction>>>    Vol Id " <<
	  " Energy (MeV) "             <<
	  " Index "                    <<
	  " Nprim "                     <<
	  " Prim1 "                      <<
	  " Prim2 "                      <<
	  " Prim3 "                      <<  endl;

      for (index = 0 ; index < dl->GetEntries() ; index++) {
	Digit = (AliPHOSDigit * )  dl->At(index) ;
	cout << "DebugReconstruction>>>  " <<
	  setw(8) <<Digit->GetId() << "  "  <<
	  setw(10) << 1000.*fClusterizer->Calibrate(Digit->GetAmp()) <<       "  "  <<
	  setw(6) <<  Digit->GetIndexInList() << "  "  <<
	  setw(5) <<  Digit->GetNprimary() <<"  "  <<
	  setw(5) <<  Digit->GetPrimary(1) <<"  "  <<
	  setw(5) <<  Digit->GetPrimary(2) <<"  "  <<
	  setw(5) <<  Digit->GetPrimary(3) << endl;
  }

    }

  if  (fDebugReconstruction)  cout << "DebugReconstruction > Start making reconstructed points (clusterizing)" << endl;
  fClusterizer->MakeClusters(dl, emccl, ppsdl);

  cout << "Emccl list entries is " << emccl->GetEntries() << endl ;
  cout << "Ppsdl list entries is " << emccl->GetEntries() << endl ;

  // mark the position of the RecPoints in the array
  AliPHOSEmcRecPoint * emcrp ;
  for (index = 0 ; index < emccl->GetEntries() ; index++) {
    emcrp = (AliPHOSEmcRecPoint * )emccl->At(index) ;
    emcrp->SetIndexInList(index) ;
  }

  AliPHOSPpsdRecPoint * ppsdrp ;
  for (index = 0 ; index < ppsdl->GetEntries() ; index++) {
    ppsdrp = (AliPHOSPpsdRecPoint * )ppsdl->At(index) ;
    ppsdrp->SetIndexInList(index) ;
  }

  cout << "Start making track segments" << endl;
  fTrackSegmentMaker->MakeTrackSegments(dl, emccl, ppsdl, trsl) ;

  // mark the position of the TrackSegments in the array
  AliPHOSTrackSegment * trs ;
  for (index = 0 ; index < trsl->GetEntries() ; index++) {
    trs = (AliPHOSTrackSegment * )trsl->At(index) ;
    trs->SetIndexInList(index) ;
  }

  cout << "Start making reconstructed particles" << endl;
  fPID->MakeParticles(trsl, rpl) ;

  // mark the position of the RecParticles in the array
  AliPHOSRecParticle * rp ;
  for (index = 0 ; index < rpl->GetEntries() ; index++) {
    rp = (AliPHOSRecParticle * )rpl->At(index) ;
    rp->SetIndexInList(index) ;
  }
}
<commit_msg>fDebugReconstruction and SetDebugReconstruction for AliPHOSReconstructioner. Debug output done in Make() member function<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//_________________________________________________________________________
//  Algorithm class for the reconstruction: clusterizer
//                                          track segment maker
//                                          particle identifier
//
//*-- Author: Gines Martinez & Yves Schutz (SUBATECH)

// --- ROOT system ---

#include "TClonesArray.h"

// --- Standard library ---

#include <iomanip>

// --- AliRoot header files ---

#include "AliPHOSReconstructioner.h"
#include "AliPHOSClusterizer.h"

ClassImp(AliPHOSReconstructioner)

//____________________________________________________________________________
AliPHOSReconstructioner::AliPHOSReconstructioner(AliPHOSClusterizer * Clusterizer,
						 AliPHOSTrackSegmentMaker * Tracker,
						 AliPHOSPID * Pid)
{
  // ctor

  fClusterizer        = Clusterizer ;
  fTrackSegmentMaker  = Tracker ;
  fPID                = Pid ;
  fDebugReconstruction = kFALSE ;
}

//____________________________________________________________________________
 void AliPHOSReconstructioner::Init(AliPHOSClusterizer * Clusterizer,
						 AliPHOSTrackSegmentMaker * Tracker,
						 AliPHOSPID * Pid)
{
  fClusterizer        = Clusterizer ;
  fTrackSegmentMaker  = Tracker ;
  fPID                = Pid ;
  fDebugReconstruction = kFALSE ;
}

//____________________________________________________________________________
 void AliPHOSReconstructioner::Make(DigitsList * dl, RecPointsList * emccl, RecPointsList * ppsdl,
				     TrackSegmentsList * trsl, RecParticlesList * rpl)
{
  // Launches the Reconstruction process in the sequence: Make the reconstructed poins (clusterize)
  //                                                      Make the track segments
  //                                                      Make the reconstructed particles

  Int_t index ;
  // Digit Debuging

  if  (fDebugReconstruction)
    {
      cout << ">>>>>>>>>>>>>>>>>>>>>> DebugReconstruction  <<<<<<<<<<<<<<<<<<<<<<<<<<"  << endl ;
      cout << "DebugReconstruction>>> Digit list entries is " <<    dl->GetEntries() << endl ;
      AliPHOSDigit * digit;
      cout << "DebugReconstruction>>>    Vol Id " <<
	  " Energy (MeV) "             <<
	  " Index "                    <<
	  " Nprim "                     <<
	  " Prim1 "                      <<
	  " Prim2 "                      <<
	  " Prim3 "                      <<  endl;

      for (index = 0 ; index < dl->GetEntries() ; index++) {
	digit = (AliPHOSDigit * )  dl->At(index) ;
	cout << "DebugReconstruction>>>  " <<
	  setw(8) << digit->GetId() << "  "  <<
	  setw(10) << 1000.*fClusterizer->Calibrate(digit->GetAmp()) <<       "  "  <<
	  setw(6) <<  digit->GetIndexInList() << "  "  <<
	  setw(5) <<  digit->GetNprimary() <<"  "  <<
	  setw(5) <<  digit->GetPrimary(1) <<"  "  <<
	  setw(5) <<  digit->GetPrimary(2) <<"  "  <<
	  setw(5) <<  digit->GetPrimary(3) << endl;
      }

    }

  // Making Clusters
  if  (fDebugReconstruction)  cout << "DebugReconstruction>>>> Start making reconstructed points (clusterizing)" << endl;
  fClusterizer->MakeClusters(dl, emccl, ppsdl);

  if  (fDebugReconstruction)
    {
      cout << ">>>>>>>>>>>>>>>>>>>>>> DebugReconstruction  <<<<<<<<<<<<<<<<<<<<<<<<<<"  << endl ;
      cout << "DebugReconstruction>>> Cluster list entries is " <<    emccl->GetEntries() << endl ;
      AliPHOSEmcRecPoint * recpoint;
      cout << "DebugReconstruction>>> Module" <<
	  "Energy(MeV)"             <<
	  "Index "                    <<
	  "Multi "                    <<
	  "   X     "                      <<
	  "   Y     "                      <<
	  "   Z    "                      <<
	  " Lambda 1   "                     <<
	  " Lambda 2   "                     <<
  	  "MaxEnergy(MeV) "                 <<
	"Nprim "                 <<
	"Prim1 "                 <<
	"Prim2 "                 <<
	"Prim3 "                 <<
endl;
      for (index = 0 ; index < emccl->GetEntries() ; index++) {
	recpoint = (AliPHOSEmcRecPoint * )emccl->At(index) ;
	TVector3  locpos;  recpoint->GetLocalPosition(locpos);
	Float_t lambda[2]; recpoint->GetElipsAxis(lambda);
	Int_t * primaries;
	Int_t nprimaries;
	primaries = recpoint->GetPrimaries(nprimaries);
	cout << "DebugReconstruction>>>  " <<
	  setw(2) <<recpoint->GetPHOSMod() << " "  <<
	  setw(9) << 1000.*recpoint->GetTotalEnergy() <<       " "  <<
	  setw(6) <<  recpoint->GetIndexInList() << " "  <<
	  setw(5) <<  recpoint->GetMultiplicity() <<" "  <<
	  setw(8) <<  locpos.X() <<" "  <<
	  setw(8) <<  locpos.Y() <<" "  <<
	  setw(8) <<  locpos.Z() << " " <<
	  setw(10) << lambda[0] << "  " <<
	  setw(10) << lambda[1] << "  " <<
	  setw(9) << 1000*recpoint->GetMaximalEnergy() << "  " <<
	  setw(9) << nprimaries << "  "  <<
	  setw(4) << primaries[0] << "  "  <<
	  setw(4) << primaries[1] << "  "  <<
	  setw(4) << primaries[2] << "  "  << endl;

      }

    }

  cout << "Ppsdl list entries is " << emccl->GetEntries() << endl ;

  // mark the position of the RecPoints in the array
  AliPHOSEmcRecPoint * emcrp ;
  for (index = 0 ; index < emccl->GetEntries() ; index++) {
    emcrp = (AliPHOSEmcRecPoint * )emccl->At(index) ;
    emcrp->SetIndexInList(index) ;
  }

  AliPHOSPpsdRecPoint * ppsdrp ;
  for (index = 0 ; index < ppsdl->GetEntries() ; index++) {
    ppsdrp = (AliPHOSPpsdRecPoint * )ppsdl->At(index) ;
    ppsdrp->SetIndexInList(index) ;
  }

  cout << "Start making track segments" << endl;
  fTrackSegmentMaker->MakeTrackSegments(dl, emccl, ppsdl, trsl) ;

  // mark the position of the TrackSegments in the array
  AliPHOSTrackSegment * trs ;
  for (index = 0 ; index < trsl->GetEntries() ; index++) {
    trs = (AliPHOSTrackSegment * )trsl->At(index) ;
    trs->SetIndexInList(index) ;
  }

  cout << "Start making reconstructed particles" << endl;
  fPID->MakeParticles(trsl, rpl) ;

  // mark the position of the RecParticles in the array
  AliPHOSRecParticle * rp ;
  for (index = 0 ; index < rpl->GetEntries() ; index++) {
    rp = (AliPHOSRecParticle * )rpl->At(index) ;
    rp->SetIndexInList(index) ;
  }
}
<|endoftext|>


<commit_before>#include <atomic>
#include <cassert>
#include <condition_variable>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <boost/program_options.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <signal.h>
#include <time.h>
#include <rados/librados.hpp>
#include "../libzlog/log_impl.h"

namespace po = boost::program_options;

static inline uint64_t __getns(clockid_t clock)
{
  struct timespec ts;
  int ret = clock_gettime(clock, &ts);
  assert(ret == 0);
  return (((uint64_t)ts.tv_sec) * 1000000000ULL) + ts.tv_nsec;
}

static inline uint64_t getns()
{
  return __getns(CLOCK_MONOTONIC);
}

static volatile int stop;
static void sigint_handler(int sig) {
  stop = 1;
}

static std::atomic<uint64_t> ios_completed;
static std::atomic<uint64_t> outstanding_ios;
static std::condition_variable io_cond;
static std::mutex io_lock;

struct aio_state {
  zlog::AioCompletion *c;
};

static void handle_aio_cb(aio_state *io)
{
  // notify workload to gen more ios
  io_lock.lock();
  outstanding_ios--;
  io_lock.unlock();
  io_cond.notify_one();

  // clean-up
  assert(io->c->ReturnValue() == 0);
  delete io->c;
  io->c = NULL;

  ios_completed++;

  delete io;
}

static void append_workload_func(zlog::Log *log, const int qdepth, int entry_size)
{
  // create random data to use for payloads
  size_t rand_buf_size = 1ULL<<23;
  std::string rand_buf;
  rand_buf.reserve(rand_buf_size);
  std::ifstream ifs("/dev/urandom", std::ios::binary | std::ios::in);
  std::copy_n(std::istreambuf_iterator<char>(ifs),
      rand_buf_size, std::back_inserter(rand_buf));
  const char *rand_buf_raw = rand_buf.c_str();

  // grab random slices from the random bytes
  std::default_random_engine generator;
  std::uniform_int_distribution<int> rand_dist;
  rand_dist = std::uniform_int_distribution<int>(0,
      rand_buf_size - entry_size - 1);

  outstanding_ios = 0;
  std::unique_lock<std::mutex> lock(io_lock);
  for (;;) {
    while (outstanding_ios < (unsigned)qdepth) {

      // create aio context
      aio_state *io = new aio_state;
      io->c = zlog::Log::aio_create_completion(
          std::bind(handle_aio_cb, io));
      assert(io->c);

      // fill with random data
      ceph::bufferlist bl;
      size_t buf_offset = rand_dist(generator);
      bl.append(rand_buf_raw + buf_offset, entry_size);

      // queue aio append operation
      int ret = log->AioAppend(io->c, bl);
      assert(ret == 0);

      outstanding_ios++;
    }

    io_cond.wait(lock, [&]{ return outstanding_ios < (unsigned)qdepth || stop; });

    if (stop)
      return;
  }

  for (;;) {
    std::cout << "draining ios: " << outstanding_ios << " remaining" << std::endl;
    if (outstanding_ios == 0)
      break;
    sleep(1);
  }
}

static void append_workload_sync_func(zlog::Log *log, int entry_size)
{
  // create random data to use for payloads
  size_t rand_buf_size = 1ULL<<23;
  std::string rand_buf;
  rand_buf.reserve(rand_buf_size);
  std::ifstream ifs("/dev/urandom", std::ios::binary | std::ios::in);
  std::copy_n(std::istreambuf_iterator<char>(ifs),
      rand_buf_size, std::back_inserter(rand_buf));
  const char *rand_buf_raw = rand_buf.c_str();

  // grab random slices from the random bytes
  std::default_random_engine generator;
  std::uniform_int_distribution<int> rand_dist;
  rand_dist = std::uniform_int_distribution<int>(0,
      rand_buf_size - entry_size - 1);

  for (;;) {
    // fill with random data
    ceph::bufferlist bl;
    size_t buf_offset = rand_dist(generator);
    bl.append(rand_buf_raw + buf_offset, entry_size);

    uint64_t pos;
    int ret = log->Append(bl, &pos);
    assert(ret == 0);

    ios_completed++;

    if (stop)
      break;
  }
}

static void nextseq_workload_func(zlog::LogImpl *log_impl)
{
  while (!stop) {
    uint64_t tail;
    int ret = log_impl->CheckTail(&tail, true);
    assert(ret == 0);

    ios_completed++;
  }
}

static void report(int stats_window, const std::string tp_log_fn)
{
  ios_completed = 0;
  uint64_t window_start = getns();

  // open the output stream
  int fd = -1;
  if (!tp_log_fn.empty()) {
    fd = open(tp_log_fn.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0440);
    assert(fd != -1);
  }

  while (!stop) {
    sleep(stats_window);

    uint64_t ios_completed_in_window = ios_completed.exchange(0);
    uint64_t window_end = getns();
    uint64_t window_dur = window_end - window_start;
    window_start = window_end;

    double iops = (double)(ios_completed_in_window *
        1000000000ULL) / (double)window_dur;

    time_t now = time(NULL);

    if (stop)
      break;

    if (fd != -1) {
      dprintf(fd, "time %llu iops %llu\n",
          (unsigned long long)now,
          (unsigned long long)iops);
    }

    std::cout << "time " << now << " iops " << (int)iops << std::endl;
  }

  if (fd != -1) {
    fsync(fd);
    close(fd);
  }
}

static void conflict(const po::variables_map& vm,
    const std::string& opt1, const std::string& opt2)
{
  if (vm.count(opt1) && !vm[opt1].defaulted() &&
      vm.count(opt2) && !vm[opt2].defaulted()) {
    throw std::logic_error(std::string("Conflicting options '") +
        opt1 + "' and '" + opt2 + "'.");
  }
}

int main(int argc, char **argv)
{
  std::string pool;
  std::string logname;
  std::string server;
  std::string port;
  int runtime;
  int stats_window;
  int qdepth;
  std::string tp_log_fn;
  int entry_size;
  int bev;
  int stripe_width;
  bool sync;

  bool append_workload;
  bool nextseq_workload;

  po::options_description gen_opts("General options");
  gen_opts.add_options()
    ("help,h", "show help message")
    ("append,a", po::bool_switch(&append_workload)->default_value(true), "append workload")
    ("nextseq,n", po::bool_switch(&nextseq_workload)->default_value(false), "next seq workload")
    ("logname,l", po::value<std::string>(&logname)->default_value(""), "Log name")
    ("server,s", po::value<std::string>(&server)->default_value("localhost"), "Server host")
    ("port,p", po::value<std::string>(&port)->default_value("5678"), "Server port")
    ("runtime,r", po::value<int>(&runtime)->default_value(0), "runtime")
    ("window", po::value<int>(&stats_window)->default_value(2), "stats collection period")
    ("pool,p", po::value<std::string>(&pool)->required(), "Pool name")
    ("iops-log", po::value<std::string>(&tp_log_fn)->default_value(""), "throughput log file")
    ("store-ver", po::value<int>(&bev)->default_value(1), "backend version")
    ("stripe-width", po::value<int>(&stripe_width)->default_value(-1), "stripe width")
    ("sync", po::bool_switch(&sync)->default_value(false), "use sync io")
  ;

  po::options_description append_opts("Append workload options");
  append_opts.add_options()
    ("entry-size,e", po::value<int>(&entry_size)->default_value(1024), "Entry size")
    ("qdepth,q", po::value<int>(&qdepth)->default_value(1), "aio queue depth")
  ;

  po::options_description all_opts("Allowed options");
  all_opts.add(gen_opts).add(append_opts);

  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, all_opts), vm);

  if (vm.count("help")) {
    std::cout << all_opts << std::endl;
    return 1;
  }

  // choose only one workload
  conflict(vm, "append", "nextseq");

  // sequencer workload doesn't perform appends
  conflict(vm, "nextseq", "entry-size");

  po::notify(vm);

  if (logname.empty()) {
    std::stringstream ss;
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    ss << uuid;
    ss << ".log";
    logname = ss.str();
  }

  if (nextseq_workload)
    append_workload = false;

  std::string workload_name;
  if (append_workload)
    workload_name = "append";
  else if (nextseq_workload)
    workload_name = "next seq";
  else
    assert(0);

  std::cout << "  workload: " << workload_name << std::endl;
  std::cout << "      pool: " << pool << std::endl;
  std::cout << "   logname: " << logname << std::endl;
  std::cout << " seqr-host: " << server << std::endl;
  std::cout << " seqr-port: " << port << std::endl;
  std::cout << "   runtime: " << runtime << std::endl;
  std::cout << "  stat win: " << stats_window << std::endl;
  std::cout << "    qdepth: " << qdepth << std::endl;
  std::cout << "  iops log: " << tp_log_fn << std::endl;
  std::cout << "entry size: " << entry_size << std::endl;
  std::cout << " store ver: " << bev << std::endl;
  std::cout << "strp width: " << stripe_width << std::endl;
  std::cout << "   sync io: " << sync << std::endl;

  assert(!pool.empty());
  assert(runtime >= 0);
  assert(stats_window > 0);
  assert(qdepth > 0);
  assert(entry_size >= 0);
  assert(bev == 1 || bev == 2);
  assert(stripe_width == -1 || stripe_width > 0);

  // connect to rados
  librados::Rados cluster;
  cluster.init(NULL);
  cluster.conf_read_file(NULL);
  int ret = cluster.connect();
  assert(ret == 0);

  // open pool i/o context
  librados::IoCtx ioctx;
  ret = cluster.ioctx_create(pool.c_str(), ioctx);
  assert(ret == 0);

  // connect to the sequencer
  zlog::SeqrClient client(server.c_str(), port.c_str());
  client.Connect();

  // open log
  zlog::Log *log;
  if (stripe_width == -1) {
    // default stripe width
    ret = zlog::Log::OpenOrCreate(ioctx, logname, &client, &log);
  } else {
    ret = zlog::Log::Open(ioctx, logname, &client, &log);
    if (ret == -ENOENT)
      ret = zlog::Log::CreateWithStripeWidth(ioctx, logname, &client, stripe_width, &log);
    if (ret == 0)
      assert(log->StripeWidth() == stripe_width);
  }
  assert(ret == 0);

  // used to access the low-level sequencer checktail interface
  zlog::LogImpl *log_impl = reinterpret_cast<zlog::LogImpl*>(log);

  // using a different backend version is a development feature and we don't
  // want to expose it through the public api yet. here we set the backend
  // version on the LogImpl object directly. All clients of the log must
  // choose the same version for every interaction with the log, and the
  // version must be set before any log I/O is performed by a client.
  switch (bev) {
    case 1:
      // this is the default case
      break;
    case 2:
      log_impl->set_backend_v2();
      break;
    default:
      assert(0);
      exit(1);
  }

  // this is a little hack that refreshes the epoch we are storing so that
  // when we send out of a bunch of async requests they don't all initially
  // fail due to an old epoch. TODO: this should probably be handled when we
  // open the log?? TODO: try without this...
  ceph::bufferlist bl;
  log->Append(bl);

  signal(SIGINT, sigint_handler);

  stop = 0;

  std::thread report_runner(report, stats_window, tp_log_fn);

  std::vector<std::thread> workload_runners;
  if (append_workload) {
    if (sync) {
      for (int i = 0; i < qdepth; i++) {
        workload_runners.push_back(std::thread(
              append_workload_sync_func, log, entry_size));
      }
    } else {
      workload_runners.push_back(std::thread(
            append_workload_func, log, qdepth, entry_size));
    }
  } else if (nextseq_workload) {
      for (int i = 0; i < qdepth; i++) {
        workload_runners.push_back(std::thread(
              nextseq_workload_func, log_impl));
      }
  } else
    assert(0);

  if (runtime) {
    sleep(runtime);
    stop = 1;
  }

  report_runner.join();
  std::for_each(workload_runners.begin(),
      workload_runners.end(), [](std::thread& t) { t.join(); });

  ioctx.close();
  cluster.shutdown();

  return 0;
}
<commit_msg>bench: be verbose on aio error<commit_after>#include <atomic>
#include <cassert>
#include <condition_variable>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <boost/program_options.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <signal.h>
#include <time.h>
#include <rados/librados.hpp>
#include "../libzlog/log_impl.h"

namespace po = boost::program_options;

static inline uint64_t __getns(clockid_t clock)
{
  struct timespec ts;
  int ret = clock_gettime(clock, &ts);
  assert(ret == 0);
  return (((uint64_t)ts.tv_sec) * 1000000000ULL) + ts.tv_nsec;
}

static inline uint64_t getns()
{
  return __getns(CLOCK_MONOTONIC);
}

static volatile int stop;
static void sigint_handler(int sig) {
  stop = 1;
}

static std::atomic<uint64_t> ios_completed;
static std::atomic<uint64_t> outstanding_ios;
static std::condition_variable io_cond;
static std::mutex io_lock;

struct aio_state {
  zlog::AioCompletion *c;
};

static void handle_aio_cb(aio_state *io)
{
  // notify workload to gen more ios
  io_lock.lock();
  outstanding_ios--;
  io_lock.unlock();
  io_cond.notify_one();

  // clean-up
  if (io->c->ReturnValue()) {
    std::cout << "error: io retval = " << io->c->ReturnValue() << std::endl;
    assert(io->c->ReturnValue() == 0);
    stop = 1;
    exit(1);
  }
  delete io->c;
  io->c = NULL;

  ios_completed++;

  delete io;
}

static void append_workload_func(zlog::Log *log, const int qdepth, int entry_size)
{
  // create random data to use for payloads
  size_t rand_buf_size = 1ULL<<23;
  std::string rand_buf;
  rand_buf.reserve(rand_buf_size);
  std::ifstream ifs("/dev/urandom", std::ios::binary | std::ios::in);
  std::copy_n(std::istreambuf_iterator<char>(ifs),
      rand_buf_size, std::back_inserter(rand_buf));
  const char *rand_buf_raw = rand_buf.c_str();

  // grab random slices from the random bytes
  std::default_random_engine generator;
  std::uniform_int_distribution<int> rand_dist;
  rand_dist = std::uniform_int_distribution<int>(0,
      rand_buf_size - entry_size - 1);

  outstanding_ios = 0;
  std::unique_lock<std::mutex> lock(io_lock);
  for (;;) {
    while (outstanding_ios < (unsigned)qdepth) {

      // create aio context
      aio_state *io = new aio_state;
      io->c = zlog::Log::aio_create_completion(
          std::bind(handle_aio_cb, io));
      assert(io->c);

      // fill with random data
      ceph::bufferlist bl;
      size_t buf_offset = rand_dist(generator);
      bl.append(rand_buf_raw + buf_offset, entry_size);

      // queue aio append operation
      int ret = log->AioAppend(io->c, bl);
      assert(ret == 0);

      outstanding_ios++;
    }

    io_cond.wait(lock, [&]{ return outstanding_ios < (unsigned)qdepth || stop; });

    if (stop)
      return;
  }

  for (;;) {
    std::cout << "draining ios: " << outstanding_ios << " remaining" << std::endl;
    if (outstanding_ios == 0)
      break;
    sleep(1);
  }
}

static void append_workload_sync_func(zlog::Log *log, int entry_size)
{
  // create random data to use for payloads
  size_t rand_buf_size = 1ULL<<23;
  std::string rand_buf;
  rand_buf.reserve(rand_buf_size);
  std::ifstream ifs("/dev/urandom", std::ios::binary | std::ios::in);
  std::copy_n(std::istreambuf_iterator<char>(ifs),
      rand_buf_size, std::back_inserter(rand_buf));
  const char *rand_buf_raw = rand_buf.c_str();

  // grab random slices from the random bytes
  std::default_random_engine generator;
  std::uniform_int_distribution<int> rand_dist;
  rand_dist = std::uniform_int_distribution<int>(0,
      rand_buf_size - entry_size - 1);

  for (;;) {
    // fill with random data
    ceph::bufferlist bl;
    size_t buf_offset = rand_dist(generator);
    bl.append(rand_buf_raw + buf_offset, entry_size);

    uint64_t pos;
    int ret = log->Append(bl, &pos);
    assert(ret == 0);

    ios_completed++;

    if (stop)
      break;
  }
}

static void nextseq_workload_func(zlog::LogImpl *log_impl)
{
  while (!stop) {
    uint64_t tail;
    int ret = log_impl->CheckTail(&tail, true);
    assert(ret == 0);

    ios_completed++;
  }
}

static void report(int stats_window, const std::string tp_log_fn)
{
  ios_completed = 0;
  uint64_t window_start = getns();

  // open the output stream
  int fd = -1;
  if (!tp_log_fn.empty()) {
    fd = open(tp_log_fn.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0440);
    assert(fd != -1);
  }

  while (!stop) {
    sleep(stats_window);

    uint64_t ios_completed_in_window = ios_completed.exchange(0);
    uint64_t window_end = getns();
    uint64_t window_dur = window_end - window_start;
    window_start = window_end;

    double iops = (double)(ios_completed_in_window *
        1000000000ULL) / (double)window_dur;

    time_t now = time(NULL);

    if (stop)
      break;

    if (fd != -1) {
      dprintf(fd, "time %llu iops %llu\n",
          (unsigned long long)now,
          (unsigned long long)iops);
    }

    std::cout << "time " << now << " iops " << (int)iops << std::endl;
  }

  if (fd != -1) {
    fsync(fd);
    close(fd);
  }
}

static void conflict(const po::variables_map& vm,
    const std::string& opt1, const std::string& opt2)
{
  if (vm.count(opt1) && !vm[opt1].defaulted() &&
      vm.count(opt2) && !vm[opt2].defaulted()) {
    throw std::logic_error(std::string("Conflicting options '") +
        opt1 + "' and '" + opt2 + "'.");
  }
}

int main(int argc, char **argv)
{
  std::string pool;
  std::string logname;
  std::string server;
  std::string port;
  int runtime;
  int stats_window;
  int qdepth;
  std::string tp_log_fn;
  int entry_size;
  int bev;
  int stripe_width;
  bool sync;

  bool append_workload;
  bool nextseq_workload;

  po::options_description gen_opts("General options");
  gen_opts.add_options()
    ("help,h", "show help message")
    ("append,a", po::bool_switch(&append_workload)->default_value(true), "append workload")
    ("nextseq,n", po::bool_switch(&nextseq_workload)->default_value(false), "next seq workload")
    ("logname,l", po::value<std::string>(&logname)->default_value(""), "Log name")
    ("server,s", po::value<std::string>(&server)->default_value("localhost"), "Server host")
    ("port,p", po::value<std::string>(&port)->default_value("5678"), "Server port")
    ("runtime,r", po::value<int>(&runtime)->default_value(0), "runtime")
    ("window", po::value<int>(&stats_window)->default_value(2), "stats collection period")
    ("pool,p", po::value<std::string>(&pool)->required(), "Pool name")
    ("iops-log", po::value<std::string>(&tp_log_fn)->default_value(""), "throughput log file")
    ("store-ver", po::value<int>(&bev)->default_value(1), "backend version")
    ("stripe-width", po::value<int>(&stripe_width)->default_value(-1), "stripe width")
    ("sync", po::bool_switch(&sync)->default_value(false), "use sync io")
  ;

  po::options_description append_opts("Append workload options");
  append_opts.add_options()
    ("entry-size,e", po::value<int>(&entry_size)->default_value(1024), "Entry size")
    ("qdepth,q", po::value<int>(&qdepth)->default_value(1), "aio queue depth")
  ;

  po::options_description all_opts("Allowed options");
  all_opts.add(gen_opts).add(append_opts);

  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, all_opts), vm);

  if (vm.count("help")) {
    std::cout << all_opts << std::endl;
    return 1;
  }

  // choose only one workload
  conflict(vm, "append", "nextseq");

  // sequencer workload doesn't perform appends
  conflict(vm, "nextseq", "entry-size");

  po::notify(vm);

  if (logname.empty()) {
    std::stringstream ss;
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    ss << uuid;
    ss << ".log";
    logname = ss.str();
  }

  if (nextseq_workload)
    append_workload = false;

  std::string workload_name;
  if (append_workload)
    workload_name = "append";
  else if (nextseq_workload)
    workload_name = "next seq";
  else
    assert(0);

  std::cout << "  workload: " << workload_name << std::endl;
  std::cout << "      pool: " << pool << std::endl;
  std::cout << "   logname: " << logname << std::endl;
  std::cout << " seqr-host: " << server << std::endl;
  std::cout << " seqr-port: " << port << std::endl;
  std::cout << "   runtime: " << runtime << std::endl;
  std::cout << "  stat win: " << stats_window << std::endl;
  std::cout << "    qdepth: " << qdepth << std::endl;
  std::cout << "  iops log: " << tp_log_fn << std::endl;
  std::cout << "entry size: " << entry_size << std::endl;
  std::cout << " store ver: " << bev << std::endl;
  std::cout << "strp width: " << stripe_width << std::endl;
  std::cout << "   sync io: " << sync << std::endl;

  assert(!pool.empty());
  assert(runtime >= 0);
  assert(stats_window > 0);
  assert(qdepth > 0);
  assert(entry_size >= 0);
  assert(bev == 1 || bev == 2);
  assert(stripe_width == -1 || stripe_width > 0);

  // connect to rados
  librados::Rados cluster;
  cluster.init(NULL);
  cluster.conf_read_file(NULL);
  int ret = cluster.connect();
  assert(ret == 0);

  // open pool i/o context
  librados::IoCtx ioctx;
  ret = cluster.ioctx_create(pool.c_str(), ioctx);
  assert(ret == 0);

  // connect to the sequencer
  zlog::SeqrClient client(server.c_str(), port.c_str());
  client.Connect();

  // open log
  zlog::Log *log;
  if (stripe_width == -1) {
    // default stripe width
    ret = zlog::Log::OpenOrCreate(ioctx, logname, &client, &log);
  } else {
    ret = zlog::Log::Open(ioctx, logname, &client, &log);
    if (ret == -ENOENT)
      ret = zlog::Log::CreateWithStripeWidth(ioctx, logname, &client, stripe_width, &log);
    if (ret == 0)
      assert(log->StripeWidth() == stripe_width);
  }
  assert(ret == 0);

  // used to access the low-level sequencer checktail interface
  zlog::LogImpl *log_impl = reinterpret_cast<zlog::LogImpl*>(log);

  // using a different backend version is a development feature and we don't
  // want to expose it through the public api yet. here we set the backend
  // version on the LogImpl object directly. All clients of the log must
  // choose the same version for every interaction with the log, and the
  // version must be set before any log I/O is performed by a client.
  switch (bev) {
    case 1:
      // this is the default case
      break;
    case 2:
      log_impl->set_backend_v2();
      break;
    default:
      assert(0);
      exit(1);
  }

  // this is a little hack that refreshes the epoch we are storing so that
  // when we send out of a bunch of async requests they don't all initially
  // fail due to an old epoch. TODO: this should probably be handled when we
  // open the log?? TODO: try without this...
  ceph::bufferlist bl;
  log->Append(bl);

  signal(SIGINT, sigint_handler);

  stop = 0;

  std::thread report_runner(report, stats_window, tp_log_fn);

  std::vector<std::thread> workload_runners;
  if (append_workload) {
    if (sync) {
      for (int i = 0; i < qdepth; i++) {
        workload_runners.push_back(std::thread(
              append_workload_sync_func, log, entry_size));
      }
    } else {
      workload_runners.push_back(std::thread(
            append_workload_func, log, qdepth, entry_size));
    }
  } else if (nextseq_workload) {
      for (int i = 0; i < qdepth; i++) {
        workload_runners.push_back(std::thread(
              nextseq_workload_func, log_impl));
      }
  } else
    assert(0);

  if (runtime) {
    sleep(runtime);
    stop = 1;
  }

  report_runner.join();
  std::for_each(workload_runners.begin(),
      workload_runners.end(), [](std::thread& t) { t.join(); });

  ioctx.close();
  cluster.shutdown();

  return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

//------------------------------------------------------------------------------
// Implementation of the AliPerformanceTask class. It checks reconstruction performance
// for the reconstructed vs MC particle tracks under several conditions. For real data
// the control QA histograms are filled.
//
// The comparison output objects deriving from AliPerformanceObject
// (e.g. AliPerformanceRes, AliPerformanceEff, AliPerformanceDEdx, AliPerformanceDCA ...)
// are stored in the output file (details in description of these classes).
//
// Author: J.Otwinowski 01/04/2009
// Changes by M.Knichel 15/10/2010
// Changes by J.Salzwedel 30/9/2014
//------------------------------------------------------------------------------

#include "iostream"

#include "TChain.h"
#include "TTree.h"
#include "TH1F.h"
#include "TCanvas.h"
#include "TList.h"
#include "TFile.h"
#include "TSystem.h"
#include "TBufferFile.h"
#include "AliAnalysisTaskSE.h"
#include "AliAnalysisManager.h"
#include "AliVEvent.h"
#include "AliVfriendEvent.h"
#include "AliMCEvent.h"
#include "AliESDInputHandler.h"
#include "AliMCEventHandler.h"
#include "AliESDVertex.h"
#include "AliMagF.h"
#include "AliTracker.h"
#include "AliGeomManager.h"
#include "AliCDBManager.h"

#include "AliCentrality.h"
#include "AliESDVZERO.h"
#include "AliMultiplicity.h"

#include "AliMCInfo.h"
#include "AliESDRecInfo.h"
#include "AliMCInfoCuts.h"
#include "AliRecInfoCuts.h"
#include "AliPerformanceObject.h"
#include "AliTPCPerformanceSummary.h"
#include "AliPerformanceTPC.h"
#include "AliPerformanceDEdx.h"
#include "AliPerformanceMatch.h"
#include "AliPerformanceTask.h"

#include <AliSysInfo.h>

using namespace std;

static bool showInfo = !(getenv("HLT_ONLINE_MODE") && strcmp(getenv("HLT_ONLINE_MODE"), "on") == 0);

ClassImp(AliPerformanceTask)

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask()
  : AliAnalysisTaskSE()
  , fVEvent(0)
  , fVfriendEvent(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(0)
  , fUseMCInfo(kFALSE)
  , fUseVfriend(kFALSE)
  , fUseHLT(kFALSE)
  , fUseTerminate(kTRUE)
  , fUseCentrality(0)
  , fUseOCDB(kTRUE)
  , fDebug(0)
  , fUseCentralityBin(0)
  , fEvents(0)
{
    // Dummy Constructor
  // should not be used
}

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask(const char *name, const char* title)
  : AliAnalysisTaskSE(name)
  , fVEvent(0)
  , fVfriendEvent(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(new TList)
  , fUseMCInfo(kFALSE)
  , fUseVfriend(kFALSE)
  , fUseHLT(kFALSE)
  , fUseTerminate(kTRUE)
  , fUseCentrality(0)
  , fUseOCDB(kTRUE)
  , fDebug(0)
  , fUseCentralityBin(0)
  , fEvents(0)
{
  // Constructor

  // Define input and output slots here
  DefineOutput(0, TTree::Class());
  DefineOutput(1, TList::Class());
}

//_____________________________________________________________________________
AliPerformanceTask::~AliPerformanceTask()
{
  if (!(AliAnalysisManager::GetAnalysisManager() && AliAnalysisManager::GetAnalysisManager()->IsProofMode())) {
    delete fOutput;
    delete fOutputSummary;
    delete fCompList;
  }
}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::AddPerformanceObject(AliPerformanceObject *pObj)
{

    // add comparison object to the list
  if(pObj == 0) {
    AliInfo("ERROR: Could not add comparison object");
    return kFALSE;
  }

  // add object to the list
  fCompList->AddLast(pObj);

return kTRUE;
}

//_____________________________________________________________________________
void AliPerformanceTask::UserCreateOutputObjects()
{
  // Create histograms
  // Called once

    // create output list
  fOutput = new TList;
  fOutput->SetOwner();
  fPitList = fOutput->MakeIterator();

  // create output list
  //fOutputSummary = new TTree;

  // add comparison objects to the output
  AliPerformanceObject *pObj=0;
  Int_t count=0;
  TIterator *pitCompList = fCompList->MakeIterator();
  pitCompList->Reset();
  while(( pObj = (AliPerformanceObject *)pitCompList->Next()) != NULL) {
    fOutput->Add(pObj);
    count++;
  }

  if (showInfo) AliInfo(Form("UserCreateOutputObjects(): Number of output comparison objects: %d", count));

  PostData(1, fOutput);
  PostData(0, fOutputSummary);
}

//_____________________________________________________________________________
void AliPerformanceTask::UserExec(Option_t *)
{
  // Main loop
  // Called for each event
  fEvents++;
  if (showInfo) AliInfo(Form("%s %s Event number %i",GetName(), GetTitle(), fEvents));
  //if(fDebug) AliSysInfo::AddStamp("memleak",fEvents);

// Decide whether to use HLT ESD or Offline ESD/AOD
  if(fUseHLT){
    AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*>
      (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());
    if(!esdH) {
      AliInfo("ERROR: Could not get ESDInputHandler");
      return;
    }
    fVEvent = esdH->GetHLTEvent();
    if(!fVEvent) {
      AliInfo("ERROR: HLTEvent unavailable from ESDInputHandler");
      return;
    }
  }// end if fUseHLT
  else {
    // Get an offline event
      AliVEventHandler *vH = AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler();
      if (!vH) {
          AliInfo("ERROR: Could not get VEventHandler");
          return;
      }
      fVEvent = vH->GetEvent();
      //fVEvent =InputEvent(); //this one does not currently work, TaskSE makes stupid assumptions about the tree
      if(!fVEvent) { AliInfo("ERROR: Event not available!"); return;}
  }

    if(fUseVfriend) {
    if (fUseHLT)
    {
        AliVEventHandler *vH = AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler();
        AliVEvent *offlineVEvent = vH->GetEvent();
        if(!offlineVEvent) {
            AliInfo("ERROR: Could not get offline event");
            return;
      }
    }
    else
    {
      fVfriendEvent = fVEvent->FindFriend();
    }

    if(!fVfriendEvent) {
      AliInfo("ERROR: ESD friends not available");
    }
  } // end if fUseVfriend

  if(fUseMCInfo) {
      //fMC = MCEvent();
  }

  if (fUseMCInfo && !fMC) {
    AliInfo("ERROR: MC event not available");
    return;
  }

  // Process analysis
  Bool_t process = kTRUE;

  // Check for centrality
  if (fUseCentrality) {
    if ( CalculateCentralityBin() != fUseCentralityBin ) {
      process = kFALSE;
    } else {
      AliInfo("wrong centrality");
    }
  }

  // Process comparison
    if(fEvents==1) fVEvent->InitMagneticField();
    if (process) {
    AliPerformanceObject *pObj=0;
    fPitList->Reset();
    while(( pObj = (AliPerformanceObject *)fPitList->Next()) != NULL) {
      //AliInfo(pObj->GetName());
      if (showInfo) AliInfo(Form("...executing job %s",pObj->GetName()));
      pObj->Exec(fMC,fVEvent,fVfriendEvent,fUseMCInfo,fUseVfriend);
    }
  }

    if(fDebug) {
        TBufferFile tempMem(TBuffer::kWrite);
        tempMem.WriteObject(fOutput);
        AliSysInfo::AddStamp("memleak",fEvents,tempMem.Length()/1024.);
    }

}

//_____________________________________________________________________________
void AliPerformanceTask::Terminate(Option_t *)
{
  // Called once at the end

  if ( !fUseTerminate )
    return;

  // check output data
    fOutputSummary = dynamic_cast<TTree*> (GetOutputData(0));
    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        AliInfo("ERROR: AliPerformanceTask::Terminate(): fOutput data not available  ..." );
        return;
   }
    if (fOutputSummary) { delete fOutputSummary; fOutputSummary=0; }
    AliPerformanceObject* pObj=0;
    AliPerformanceTPC*  pTPC = 0;
    AliPerformanceDEdx* pDEdx = 0;
    AliPerformanceMatch* pMatch = 0;
    AliPerformanceMatch* pPull = 0;
    AliPerformanceMatch* pConstrain = 0;
    TIterator* itOut = fOutput->MakeIterator();
    itOut->Reset();
    while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
      pObj->AnalyseFinal();
      /*      if (!  pTPC)  {    pTPC = dynamic_cast<AliPerformanceTPC*>(pObj); }
        if (! pDEdx)  {   pDEdx = dynamic_cast<AliPerformanceDEdx*>(pObj); }
        if (! pMatch) {  pMatch = dynamic_cast<AliPerformanceMatch*>(pObj); }
        if ((! pPull) && pMatch ) {  pPull = dynamic_cast<AliPerformanceMatch*>(pObj);*/

	if (!strcmp(pObj->GetName(),"AliPerformanceTPC"))  {    pTPC = dynamic_cast<AliPerformanceTPC*>(pObj); }
        if (!strcmp(pObj->GetName(),"AliPerformanceDEdxTPCInner"))  {   pDEdx = dynamic_cast<AliPerformanceDEdx*>(pObj); }
        if (!strcmp(pObj->GetName(),"AliPerformanceMatchTPCITS")) {  pMatch = dynamic_cast<AliPerformanceMatch*>(pObj); }
        if (!strcmp(pObj->GetName(),"AliPerformanceMatchITSTPC")) {  pPull = dynamic_cast<AliPerformanceMatch*>(pObj);}
        if (!strcmp(pObj->GetName(),"AliPerformanceMatchTPCConstrain")) {  pConstrain = dynamic_cast<AliPerformanceMatch*>(pObj);}
    }

    if(!fUseOCDB)  {
      AliInfo("DO NOT USE OCDB");
      return;
    }

/*    if (! AliCDBManager::Instance()->GetDefaultStorage()) { AliCDBManager::Instance()->SetDefaultStorage("raw://"); }
    TUUID uuid;
    TString tmpFile = gSystem->TempDirectory() + TString("/TPCQASummary.") + uuid.AsString() + TString(".root");
    AliTPCPerformanceSummary::WriteToFile(pTPC, pDEdx, pMatch, pPull, pConstrain, tmpFile.Data());
    TChain* chain = new TChain("tpcQA");
    if(!chain) return;
    chain->Add(tmpFile.Data());
    TTree *tree = chain->CopyTree("1");
    if (chain) { delete chain; chain=0; }
    fOutputSummary = tree;*/

//      // Post output data.
//      PostData(0, fOutputSummary);

}

//_____________________________________________________________________________
void AliPerformanceTask::FinishTaskOutput()
{
    // called once at the end of each job (on the workernode)
    //
    // projects THnSparse to TH1,2,3

    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        AliInfo("ERROR: AliPerformanceTask::FinishTaskOutput(): fOutput data not available  ..." );
        return;
   }

      AliPerformanceObject* pObj=0;
      TIterator* itOut = fOutput->MakeIterator();
      itOut->Reset();
      while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
          //pObj->SetRunNumber(fCurrentRunNumber);
          pObj->Analyse();
      }

    if(fDebug) {
        TBufferFile tempMem(TBuffer::kWrite);
        tempMem.WriteObject(fOutput);
        AliSysInfo::AddStamp("memleak",fEvents+1,tempMem.Length()/1024.);
    }

     // Post output data.
     //PostData(1, fOutput);
     //PostData(0, fOutputSummary);

}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::Notify()
{
  static Int_t count = 0;
  count++;
  AliInfo(Form("Processing %d. file", count));

  return kTRUE;
}

//________________________________________________________________________
Int_t AliPerformanceTask::CalculateCentralityBin(){
  // Get Centrality bin

  Int_t centrality = -1;
  Float_t centralityF = -1;

  if (fUseCentrality == 0)
    return centrality;

  AliCentrality *eventCentrality = NULL;
  if(fVEvent) eventCentrality = fVEvent->GetCentrality();
  if(!eventCentrality) {
    AliInfo("ERROR: Could not obtain event centrality");
    return centrality;
  }
  // New : 2010-11-18 JMT
  if ( fUseCentrality == 1 )
    centralityF = eventCentrality->GetCentralityPercentile("V0M");
  else if ( fUseCentrality == 2 )
    centralityF = eventCentrality->GetCentralityPercentile("CL1");
  else if ( fUseCentrality == 3 )
    centralityF = eventCentrality->GetCentralityPercentile("TRK");
  if (centralityF == 0.)
    centralityF = 100.;

  if      ( centralityF >=  0. && centralityF <   5.) centrality =  0;
  else if ( centralityF >=  5. && centralityF <  10.) centrality =  5;
  else if ( centralityF >= 10. && centralityF <  20.) centrality = 10;
  else if ( centralityF >= 20. && centralityF <  30.) centrality = 20;
  else if ( centralityF >= 30. && centralityF <  40.) centrality = 30;
  else if ( centralityF >= 40. && centralityF <  50.) centrality = 40;
  else if ( centralityF >= 50. && centralityF <  60.) centrality = 50;
  else if ( centralityF >= 60. && centralityF <  70.) centrality = 60;
  else if ( centralityF >= 70. && centralityF <  80.) centrality = 70;
  else if ( centralityF >= 80. && centralityF <  90.) centrality = 80;
  else if ( centralityF >= 90. && centralityF <=100.) centrality = 90;

  return centrality;
}

//________________________________________________________________________
Bool_t AliPerformanceTask::ResetOutputData(){

    AliPerformanceObject* pObj=0;
    TIterator* itOut = fOutput->MakeIterator();
    itOut->Reset();

    while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
      pObj->ResetOutputData();
    }

    return kFALSE;
}
<commit_msg>Fix attaching of the MC event and friend event for HLT QA<commit_after>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

//------------------------------------------------------------------------------
// Implementation of the AliPerformanceTask class. It checks reconstruction performance
// for the reconstructed vs MC particle tracks under several conditions. For real data
// the control QA histograms are filled.
//
// The comparison output objects deriving from AliPerformanceObject
// (e.g. AliPerformanceRes, AliPerformanceEff, AliPerformanceDEdx, AliPerformanceDCA ...)
// are stored in the output file (details in description of these classes).
//
// Author: J.Otwinowski 01/04/2009
// Changes by M.Knichel 15/10/2010
// Changes by J.Salzwedel 30/9/2014
//------------------------------------------------------------------------------

#include "iostream"

#include "TChain.h"
#include "TTree.h"
#include "TH1F.h"
#include "TCanvas.h"
#include "TList.h"
#include "TFile.h"
#include "TSystem.h"
#include "TBufferFile.h"
#include "AliAnalysisTaskSE.h"
#include "AliAnalysisManager.h"
#include "AliVEvent.h"
#include "AliVfriendEvent.h"
#include "AliMCEvent.h"
#include "AliESDInputHandler.h"
#include "AliMCEventHandler.h"
#include "AliESDVertex.h"
#include "AliMagF.h"
#include "AliTracker.h"
#include "AliGeomManager.h"
#include "AliCDBManager.h"

#include "AliCentrality.h"
#include "AliESDVZERO.h"
#include "AliMultiplicity.h"

#include "AliMCInfo.h"
#include "AliESDRecInfo.h"
#include "AliMCInfoCuts.h"
#include "AliRecInfoCuts.h"
#include "AliPerformanceObject.h"
#include "AliTPCPerformanceSummary.h"
#include "AliPerformanceTPC.h"
#include "AliPerformanceDEdx.h"
#include "AliPerformanceMatch.h"
#include "AliPerformanceTask.h"

#include <AliSysInfo.h>

using namespace std;

static bool showInfo = !(getenv("HLT_ONLINE_MODE") && strcmp(getenv("HLT_ONLINE_MODE"), "on") == 0);

ClassImp(AliPerformanceTask)

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask()
  : AliAnalysisTaskSE()
  , fVEvent(0)
  , fVfriendEvent(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(0)
  , fUseMCInfo(kFALSE)
  , fUseVfriend(kFALSE)
  , fUseHLT(kFALSE)
  , fUseTerminate(kTRUE)
  , fUseCentrality(0)
  , fUseOCDB(kTRUE)
  , fDebug(0)
  , fUseCentralityBin(0)
  , fEvents(0)
{
    // Dummy Constructor
  // should not be used
}

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask(const char *name, const char* title)
  : AliAnalysisTaskSE(name)
  , fVEvent(0)
  , fVfriendEvent(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(new TList)
  , fUseMCInfo(kFALSE)
  , fUseVfriend(kFALSE)
  , fUseHLT(kFALSE)
  , fUseTerminate(kTRUE)
  , fUseCentrality(0)
  , fUseOCDB(kTRUE)
  , fDebug(0)
  , fUseCentralityBin(0)
  , fEvents(0)
{
  // Constructor

  // Define input and output slots here
  DefineOutput(0, TTree::Class());
  DefineOutput(1, TList::Class());
}

//_____________________________________________________________________________
AliPerformanceTask::~AliPerformanceTask()
{
  if (!(AliAnalysisManager::GetAnalysisManager() && AliAnalysisManager::GetAnalysisManager()->IsProofMode())) {
    delete fOutput;
    delete fOutputSummary;
    delete fCompList;
  }
}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::AddPerformanceObject(AliPerformanceObject *pObj)
{

    // add comparison object to the list
  if(pObj == 0) {
    AliInfo("ERROR: Could not add comparison object");
    return kFALSE;
  }

  // add object to the list
  fCompList->AddLast(pObj);

return kTRUE;
}

//_____________________________________________________________________________
void AliPerformanceTask::UserCreateOutputObjects()
{
  // Create histograms
  // Called once

    // create output list
  fOutput = new TList;
  fOutput->SetOwner();
  fPitList = fOutput->MakeIterator();

  // create output list
  //fOutputSummary = new TTree;

  // add comparison objects to the output
  AliPerformanceObject *pObj=0;
  Int_t count=0;
  TIterator *pitCompList = fCompList->MakeIterator();
  pitCompList->Reset();
  while(( pObj = (AliPerformanceObject *)pitCompList->Next()) != NULL) {
    fOutput->Add(pObj);
    count++;
  }

  if (showInfo) AliInfo(Form("UserCreateOutputObjects(): Number of output comparison objects: %d", count));

  PostData(1, fOutput);
  PostData(0, fOutputSummary);
}

//_____________________________________________________________________________
void AliPerformanceTask::UserExec(Option_t *)
{
  // Main loop
  // Called for each event
  fEvents++;
  if (showInfo) AliInfo(Form("%s %s Event number %i",GetName(), GetTitle(), fEvents));
  //if(fDebug) AliSysInfo::AddStamp("memleak",fEvents);

// Decide whether to use HLT ESD or Offline ESD/AOD
  if(fUseHLT){
    AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*>
      (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());
    if(!esdH) {
      AliInfo("ERROR: Could not get ESDInputHandler");
      return;
    }
    fVEvent = esdH->GetHLTEvent();
    if(!fVEvent) {
      AliInfo("ERROR: HLTEvent unavailable from ESDInputHandler");
      return;
    }
  }// end if fUseHLT
  else {
    // Get an offline event
      AliVEventHandler *vH = AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler();
      if (!vH) {
          AliInfo("ERROR: Could not get VEventHandler");
          return;
      }
      fVEvent = vH->GetEvent();
      //fVEvent =InputEvent(); //this one does not currently work, TaskSE makes stupid assumptions about the tree
      if(!fVEvent) { AliInfo("ERROR: Event not available!"); return;}
  }

    if(fUseVfriend) {
    if (fUseHLT)
    {
        AliVEventHandler *vH = AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler();
        AliVEvent *offlineVEvent = vH->GetEvent();
        if(!offlineVEvent) {
            AliInfo("ERROR: Could not get offline event");
            return;
      }
      fVfriendEvent = fVEvent->FindFriend();
    }
    else
    {
      fVfriendEvent = fVEvent->FindFriend();
    }

    if(!fVfriendEvent) {
      AliInfo("ERROR: ESD friends not available");
    }
  } // end if fUseVfriend

  if(fUseMCInfo) {
      fMC = MCEvent();
  }

  if (fUseMCInfo && !fMC) {
    AliInfo("ERROR: MC event not available");
    return;
  }

  // Process analysis
  Bool_t process = kTRUE;

  // Check for centrality
  if (fUseCentrality) {
    if ( CalculateCentralityBin() != fUseCentralityBin ) {
      process = kFALSE;
    } else {
      AliInfo("wrong centrality");
    }
  }

  // Process comparison
    if(fEvents==1) fVEvent->InitMagneticField();
    if (process) {
    AliPerformanceObject *pObj=0;
    fPitList->Reset();
    while(( pObj = (AliPerformanceObject *)fPitList->Next()) != NULL) {
      //AliInfo(pObj->GetName());
      if (showInfo) AliInfo(Form("...executing job %s",pObj->GetName()));
      pObj->Exec(fMC,fVEvent,fVfriendEvent,fUseMCInfo,fUseVfriend);
    }
  }

    if(fDebug) {
        TBufferFile tempMem(TBuffer::kWrite);
        tempMem.WriteObject(fOutput);
        AliSysInfo::AddStamp("memleak",fEvents,tempMem.Length()/1024.);
    }

}

//_____________________________________________________________________________
void AliPerformanceTask::Terminate(Option_t *)
{
  // Called once at the end

  if ( !fUseTerminate )
    return;

  // check output data
    fOutputSummary = dynamic_cast<TTree*> (GetOutputData(0));
    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        AliInfo("ERROR: AliPerformanceTask::Terminate(): fOutput data not available  ..." );
        return;
   }
    if (fOutputSummary) { delete fOutputSummary; fOutputSummary=0; }
    AliPerformanceObject* pObj=0;
    AliPerformanceTPC*  pTPC = 0;
    AliPerformanceDEdx* pDEdx = 0;
    AliPerformanceMatch* pMatch = 0;
    AliPerformanceMatch* pPull = 0;
    AliPerformanceMatch* pConstrain = 0;
    TIterator* itOut = fOutput->MakeIterator();
    itOut->Reset();
    while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
      pObj->AnalyseFinal();
      /*      if (!  pTPC)  {    pTPC = dynamic_cast<AliPerformanceTPC*>(pObj); }
        if (! pDEdx)  {   pDEdx = dynamic_cast<AliPerformanceDEdx*>(pObj); }
        if (! pMatch) {  pMatch = dynamic_cast<AliPerformanceMatch*>(pObj); }
        if ((! pPull) && pMatch ) {  pPull = dynamic_cast<AliPerformanceMatch*>(pObj);*/

	if (!strcmp(pObj->GetName(),"AliPerformanceTPC"))  {    pTPC = dynamic_cast<AliPerformanceTPC*>(pObj); }
        if (!strcmp(pObj->GetName(),"AliPerformanceDEdxTPCInner"))  {   pDEdx = dynamic_cast<AliPerformanceDEdx*>(pObj); }
        if (!strcmp(pObj->GetName(),"AliPerformanceMatchTPCITS")) {  pMatch = dynamic_cast<AliPerformanceMatch*>(pObj); }
        if (!strcmp(pObj->GetName(),"AliPerformanceMatchITSTPC")) {  pPull = dynamic_cast<AliPerformanceMatch*>(pObj);}
        if (!strcmp(pObj->GetName(),"AliPerformanceMatchTPCConstrain")) {  pConstrain = dynamic_cast<AliPerformanceMatch*>(pObj);}
    }

    if(!fUseOCDB)  {
      AliInfo("DO NOT USE OCDB");
      return;
    }

/*    if (! AliCDBManager::Instance()->GetDefaultStorage()) { AliCDBManager::Instance()->SetDefaultStorage("raw://"); }
    TUUID uuid;
    TString tmpFile = gSystem->TempDirectory() + TString("/TPCQASummary.") + uuid.AsString() + TString(".root");
    AliTPCPerformanceSummary::WriteToFile(pTPC, pDEdx, pMatch, pPull, pConstrain, tmpFile.Data());
    TChain* chain = new TChain("tpcQA");
    if(!chain) return;
    chain->Add(tmpFile.Data());
    TTree *tree = chain->CopyTree("1");
    if (chain) { delete chain; chain=0; }
    fOutputSummary = tree;*/

//      // Post output data.
//      PostData(0, fOutputSummary);

}

//_____________________________________________________________________________
void AliPerformanceTask::FinishTaskOutput()
{
    // called once at the end of each job (on the workernode)
    //
    // projects THnSparse to TH1,2,3

    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        AliInfo("ERROR: AliPerformanceTask::FinishTaskOutput(): fOutput data not available  ..." );
        return;
   }

      AliPerformanceObject* pObj=0;
      TIterator* itOut = fOutput->MakeIterator();
      itOut->Reset();
      while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
          //pObj->SetRunNumber(fCurrentRunNumber);
          pObj->Analyse();
      }

    if(fDebug) {
        TBufferFile tempMem(TBuffer::kWrite);
        tempMem.WriteObject(fOutput);
        AliSysInfo::AddStamp("memleak",fEvents+1,tempMem.Length()/1024.);
    }

     // Post output data.
     //PostData(1, fOutput);
     //PostData(0, fOutputSummary);

}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::Notify()
{
  static Int_t count = 0;
  count++;
  AliInfo(Form("Processing %d. file", count));

  return kTRUE;
}

//________________________________________________________________________
Int_t AliPerformanceTask::CalculateCentralityBin(){
  // Get Centrality bin

  Int_t centrality = -1;
  Float_t centralityF = -1;

  if (fUseCentrality == 0)
    return centrality;

  AliCentrality *eventCentrality = NULL;
  if(fVEvent) eventCentrality = fVEvent->GetCentrality();
  if(!eventCentrality) {
    AliInfo("ERROR: Could not obtain event centrality");
    return centrality;
  }
  // New : 2010-11-18 JMT
  if ( fUseCentrality == 1 )
    centralityF = eventCentrality->GetCentralityPercentile("V0M");
  else if ( fUseCentrality == 2 )
    centralityF = eventCentrality->GetCentralityPercentile("CL1");
  else if ( fUseCentrality == 3 )
    centralityF = eventCentrality->GetCentralityPercentile("TRK");
  if (centralityF == 0.)
    centralityF = 100.;

  if      ( centralityF >=  0. && centralityF <   5.) centrality =  0;
  else if ( centralityF >=  5. && centralityF <  10.) centrality =  5;
  else if ( centralityF >= 10. && centralityF <  20.) centrality = 10;
  else if ( centralityF >= 20. && centralityF <  30.) centrality = 20;
  else if ( centralityF >= 30. && centralityF <  40.) centrality = 30;
  else if ( centralityF >= 40. && centralityF <  50.) centrality = 40;
  else if ( centralityF >= 50. && centralityF <  60.) centrality = 50;
  else if ( centralityF >= 60. && centralityF <  70.) centrality = 60;
  else if ( centralityF >= 70. && centralityF <  80.) centrality = 70;
  else if ( centralityF >= 80. && centralityF <  90.) centrality = 80;
  else if ( centralityF >= 90. && centralityF <=100.) centrality = 90;

  return centrality;
}

//________________________________________________________________________
Bool_t AliPerformanceTask::ResetOutputData(){

    AliPerformanceObject* pObj=0;
    TIterator* itOut = fOutput->MakeIterator();
    itOut->Reset();

    while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
      pObj->ResetOutputData();
    }

    return kFALSE;
}
<|endoftext|>


<commit_before>

#include "stdafx.h"
#include "GStreamerCore.h"

#include "UnityHelpers.h"
#include <IThreadManager.h>

#include <gst/app/gstappsink.h>
#include <gst/video/video.h>

#include <glib-object.h>
#include <glib.h>
#include <algorithm>

#if false
#include "CMySrc.h"
#include "CMySink.h"
#endif

#ifdef USE_UNITY_NETWORK
#include "CMyUDPSrc.h"
#include "CMyUDPSink.h"
#include "CMyListener.h"
#endif

#ifdef __ANDROID__

void
gst_android_register_static_plugins(void);
/* Call this function to load GIO modules */
void
gst_android_load_gio_modules(void);
#endif

namespace mray
{
namespace video
{

GStreamerCore* GStreamerCore::m_instance=0;
uint GStreamerCore::m_refCount = 0;

static gboolean appsink_plugin_init(GstPlugin * plugin)
{
	gst_element_register(plugin, "appsink", GST_RANK_NONE, GST_TYPE_APP_SINK);

	return TRUE;
}

class GstMainLoopThread : public OS::IThreadFunction{
public:
	GMainLoop *main_loop;
	GstMainLoopThread()
		:main_loop(NULL)
	{

	}

	void setup(){
		//			startThread();
	}
	void execute(OS::IThread*caller, void*arg){
		main_loop = g_main_loop_new(NULL, FALSE);
		g_main_loop_run(main_loop);
		LogMessage("GST Thread shutdown",ELL_INFO);
	}
};

GStreamerCore::GStreamerCore()
{
	gub_main_loop_thread = 0;
	gub_main_loop = 0;
	_Init();
}

GStreamerCore::~GStreamerCore()
{
	_StopLoop();
	gst_deinit();
}

void g_logFunction(const gchar   *log_domain,
	GLogLevelFlags log_level,
	const gchar   *message,
	gpointer       user_data)
{
    if(log_level==G_LOG_LEVEL_INFO || log_level==G_LOG_LEVEL_DEBUG)
        LogMessage(message, ELL_INFO);
    else if(log_level==G_LOG_LEVEL_WARNING)
        LogMessage(message, ELL_WARNING);
    else if(log_level==G_LOG_LEVEL_CRITICAL || log_level==G_LOG_FLAG_FATAL)
        LogMessage(message, ELL_ERROR);
    else
        LogMessage(message, ELL_INFO);
}

gpointer gst_main_loop_func(gpointer data)
{
	GStreamerCore* core = (GStreamerCore*)data;
	core->_loopFunction();

	return NULL;
}

void GStreamerCore::_Init()
{

	GError *err = 0;
	_gst_debug_enabled = false;
	if (!gst_init_check(0,0, &err))
	{
		LogManager::Instance()->LogMessage("GStreamerCore - Failed to init GStreamer!");
	}
	else
    {
        g_log_set_handler(0,  G_LOG_LEVEL_WARNING, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_MESSAGE, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_INFO, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_DEBUG, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_CRITICAL, g_logFunction, 0);
		g_log_set_handler(0, G_LOG_FLAG_FATAL , g_logFunction, 0);
		g_log_set_default_handler(g_logFunction, 0);

#if defined (__ANDROID__)
		//gst_android_register_static_plugins();
		//gst_android_load_gio_modules();
#endif

        LogManager::Instance()->LogMessage("GStreamerCore - Registering Elements!");
		//fclose(stderr);

		//register plugin path

		//std::string gst_path = g_getenv("GSTREAMER_1_0_ROOT_X86_64");
		//putenv(("GST_PLUGIN_PATH_1_0=" + gst_path + "lib\\gstreamer-1.0" + ";.").c_str());
        //add our custom src/sink elements
#ifdef USE_UNITY_NETWORK
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"appsink", (char*)"Element application sink",
			appsink_plugin_init, "0.1", "LGPL", "ofVideoPlayer", "openFrameworks",
                                   "http://openframeworks.cc/");
	/*	gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"mysrc", (char*)"Element application src",
			_GstMySrcClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"mysink", (char*)"Element application sink",
			_GstMySinkClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
                                   "");*/
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"myudpsrc", (char*)"Element udp src",
			_GstMyUDPSrcClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"myudpsink", (char*)"Element udp sink",
			_GstMyUDPSinkClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");

		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"mylistener", (char*)"Custom listener element",
			_GstMyListenerClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");
#endif
		LogManager::Instance()->LogMessage("GStreamerCore - GStreamer inited");
	}

#if GLIB_MINOR_VERSION<32
	if (!g_thread_supported()){
		g_thread_init(NULL);
	}
#endif

	gub_main_loop_thread = g_thread_new("GstUnityBridge Main Thread", gst_main_loop_func, this);
	if (!gub_main_loop_thread) {
		LogManager::Instance()->LogMessage(std::string("Failed to create GLib main thread: ") + std::string(err ? err->message : "<No error message>"));
		return;
	}

	_StartLoop();
}

void GStreamerCore::_loopFunction() {
	LogManager::Instance()->LogMessage("Entering main loop");
	gub_main_loop = g_main_loop_new(NULL, FALSE);
	g_main_loop_run(gub_main_loop);
	LogManager::Instance()->LogMessage("Quitting main loop");
}

void GStreamerCore::_StartLoop()
{
	/*m_threadFunc = new GstMainLoopThread();
	m_mainLoopThread = OS::IThreadManager::getInstance().createThread(m_threadFunc);
	m_mainLoopThread->start(0);*/
}

void GStreamerCore::_StopLoop()
{
	/*
	if (!m_threadFunc)
		return;
	GstMainLoopThread* mainLoop = (GstMainLoopThread*)m_threadFunc;
	g_main_loop_quit(mainLoop->main_loop);
	bool running = g_main_loop_is_running(mainLoop->main_loop);
	g_main_loop_unref(mainLoop->main_loop);
	delete m_threadFunc;
	OS::IThreadManager::getInstance().killThread(m_mainLoopThread);
	delete m_mainLoopThread;
	m_threadFunc = 0;
	m_mainLoopThread = 0;
	*/

	if (!gub_main_loop) {
		return;
	}
	g_main_loop_quit(gub_main_loop);
	gub_main_loop = NULL;
	g_thread_join(gub_main_loop_thread);
	gub_main_loop_thread = NULL;
}

void GStreamerCore::Ref()
{
	m_refCount++;
	if (m_refCount==1)
	{
		LogManager::Instance()->LogMessage("Initializing GStreamer");
		m_instance = new GStreamerCore();
		LogManager::Instance()->LogMessage("Initializing GStreamer - Done");
	}

}

void GStreamerCore::Unref()
{
	if (m_refCount == 0)
	{
		LogMessage("GStreamerCore::Unref() - unreferencing GStreamer with no reference! ", ELL_ERROR);
		return;
	}
	//m_refCount--;
	if (m_refCount == 0)
	{
		delete m_instance;
		m_instance = 0;
	}
}

GStreamerCore* GStreamerCore::Instance()
{
	return m_instance;
}

}
}

<commit_msg>Fix GLib errors being logged as info instead of error in logs<commit_after>

#include "stdafx.h"
#include "GStreamerCore.h"

#include "UnityHelpers.h"
#include <IThreadManager.h>

#include <gst/app/gstappsink.h>
#include <gst/video/video.h>

#include <glib-object.h>
#include <glib.h>
#include <algorithm>

#if false
#include "CMySrc.h"
#include "CMySink.h"
#endif

#ifdef USE_UNITY_NETWORK
#include "CMyUDPSrc.h"
#include "CMyUDPSink.h"
#include "CMyListener.h"
#endif

#ifdef __ANDROID__

void
gst_android_register_static_plugins(void);
/* Call this function to load GIO modules */
void
gst_android_load_gio_modules(void);
#endif

namespace mray
{
namespace video
{

GStreamerCore* GStreamerCore::m_instance=0;
uint GStreamerCore::m_refCount = 0;

static gboolean appsink_plugin_init(GstPlugin * plugin)
{
	gst_element_register(plugin, "appsink", GST_RANK_NONE, GST_TYPE_APP_SINK);

	return TRUE;
}

class GstMainLoopThread : public OS::IThreadFunction{
public:
	GMainLoop *main_loop;
	GstMainLoopThread()
		:main_loop(NULL)
	{

	}

	void setup(){
		//			startThread();
	}
	void execute(OS::IThread*caller, void*arg){
		main_loop = g_main_loop_new(NULL, FALSE);
		g_main_loop_run(main_loop);
		LogMessage("GST Thread shutdown",ELL_INFO);
	}
};

GStreamerCore::GStreamerCore()
{
	gub_main_loop_thread = 0;
	gub_main_loop = 0;
	_Init();
}

GStreamerCore::~GStreamerCore()
{
	_StopLoop();
	gst_deinit();
}

void g_logFunction(const gchar   *log_domain,
	GLogLevelFlags log_level,
	const gchar   *message,
	gpointer       user_data)
{
    if(log_level==G_LOG_LEVEL_INFO || log_level==G_LOG_LEVEL_DEBUG)
        LogMessage(message, ELL_INFO);
    else if(log_level==G_LOG_LEVEL_WARNING)
        LogMessage(message, ELL_WARNING);
    else if(log_level==G_LOG_LEVEL_CRITICAL || log_level==G_LOG_FLAG_FATAL || log_level==G_LOG_LEVEL_ERROR)
        LogMessage(message, ELL_ERROR);
    else
        LogMessage(message, ELL_INFO);
}

gpointer gst_main_loop_func(gpointer data)
{
	GStreamerCore* core = (GStreamerCore*)data;
	core->_loopFunction();

	return NULL;
}

void GStreamerCore::_Init()
{

	GError *err = 0;
	_gst_debug_enabled = false;
	if (!gst_init_check(0,0, &err))
	{
		LogManager::Instance()->LogMessage("GStreamerCore - Failed to init GStreamer!");
	}
	else
    {
        g_log_set_handler(0,  G_LOG_LEVEL_WARNING, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_MESSAGE, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_INFO, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_DEBUG, g_logFunction, 0);
        g_log_set_handler(0,  G_LOG_LEVEL_CRITICAL, g_logFunction, 0);
		g_log_set_handler(0, G_LOG_FLAG_FATAL , g_logFunction, 0);
		g_log_set_default_handler(g_logFunction, 0);

#if defined (__ANDROID__)
		//gst_android_register_static_plugins();
		//gst_android_load_gio_modules();
#endif

        LogManager::Instance()->LogMessage("GStreamerCore - Registering Elements!");
		//fclose(stderr);

		//register plugin path

		//std::string gst_path = g_getenv("GSTREAMER_1_0_ROOT_X86_64");
		//putenv(("GST_PLUGIN_PATH_1_0=" + gst_path + "lib\\gstreamer-1.0" + ";.").c_str());
        //add our custom src/sink elements
#ifdef USE_UNITY_NETWORK
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"appsink", (char*)"Element application sink",
			appsink_plugin_init, "0.1", "LGPL", "ofVideoPlayer", "openFrameworks",
                                   "http://openframeworks.cc/");
	/*	gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"mysrc", (char*)"Element application src",
			_GstMySrcClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"mysink", (char*)"Element application sink",
			_GstMySinkClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
                                   "");*/
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"myudpsrc", (char*)"Element udp src",
			_GstMyUDPSrcClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");
		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"myudpsink", (char*)"Element udp sink",
			_GstMyUDPSinkClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");

		gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
			"mylistener", (char*)"Custom listener element",
			_GstMyListenerClass::plugin_init, "0.1", "LGPL", "GstVideoProvider", "mray",
			"");
#endif
		LogManager::Instance()->LogMessage("GStreamerCore - GStreamer inited");
	}

#if GLIB_MINOR_VERSION<32
	if (!g_thread_supported()){
		g_thread_init(NULL);
	}
#endif

	gub_main_loop_thread = g_thread_new("GstUnityBridge Main Thread", gst_main_loop_func, this);
	if (!gub_main_loop_thread) {
		LogManager::Instance()->LogMessage(std::string("Failed to create GLib main thread: ") + std::string(err ? err->message : "<No error message>"));
		return;
	}

	_StartLoop();
}

void GStreamerCore::_loopFunction() {
	LogManager::Instance()->LogMessage("Entering main loop");
	gub_main_loop = g_main_loop_new(NULL, FALSE);
	g_main_loop_run(gub_main_loop);
	LogManager::Instance()->LogMessage("Quitting main loop");
}

void GStreamerCore::_StartLoop()
{
	/*m_threadFunc = new GstMainLoopThread();
	m_mainLoopThread = OS::IThreadManager::getInstance().createThread(m_threadFunc);
	m_mainLoopThread->start(0);*/
}

void GStreamerCore::_StopLoop()
{
	/*
	if (!m_threadFunc)
		return;
	GstMainLoopThread* mainLoop = (GstMainLoopThread*)m_threadFunc;
	g_main_loop_quit(mainLoop->main_loop);
	bool running = g_main_loop_is_running(mainLoop->main_loop);
	g_main_loop_unref(mainLoop->main_loop);
	delete m_threadFunc;
	OS::IThreadManager::getInstance().killThread(m_mainLoopThread);
	delete m_mainLoopThread;
	m_threadFunc = 0;
	m_mainLoopThread = 0;
	*/

	if (!gub_main_loop) {
		return;
	}
	g_main_loop_quit(gub_main_loop);
	gub_main_loop = NULL;
	g_thread_join(gub_main_loop_thread);
	gub_main_loop_thread = NULL;
}

void GStreamerCore::Ref()
{
	m_refCount++;
	if (m_refCount==1)
	{
		LogManager::Instance()->LogMessage("Initializing GStreamer");
		m_instance = new GStreamerCore();
		LogManager::Instance()->LogMessage("Initializing GStreamer - Done");
	}

}

void GStreamerCore::Unref()
{
	if (m_refCount == 0)
	{
		LogMessage("GStreamerCore::Unref() - unreferencing GStreamer with no reference! ", ELL_ERROR);
		return;
	}
	//m_refCount--;
	if (m_refCount == 0)
	{
		delete m_instance;
		m_instance = 0;
	}
}

GStreamerCore* GStreamerCore::Instance()
{
	return m_instance;
}

}
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Jari Saukkonen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <Arduino.h>

#ifdef CORE_TEENSY_RAWHID

#include "AnalogInput.h"
#include "HubConfiguration.h"
#include "PowerOutputs.h"
#include "SkyQuality.h"
#include "SkyTemperature.h"
#include "TemperatureSensors.h"
#include "USB.h"
#include "USBCommands.h"
#include "Weather.h"
#include "Version.h"
#include "VoltageMonitor.h"

static uint8_t usbSendBuffer[64];
static uint8_t usbRecvBuffer[64];

HubConfiguration* USB::hubConfiguration;

void USB::loop() {
    int available = RawHID.available();
    if (available > 0) {
        memset(usbSendBuffer, 0, 64);
        RawHID.recv(usbRecvBuffer, available);
        handleCommands(usbRecvBuffer, available);
    }
}

void USB::handleCommands(uint8_t* data, unsigned int maxlen) {
    unsigned int pos = 0;
    if (data[pos++] != 'K')
        return;

    while (pos < maxlen) {
        uint8_t command = data[pos++];
        switch (command) {
            case END: {
                return;
            }

            case GETFACTORYSETTINGS: {
                const HubConfiguration::FactoryConfig& factoryConfig = hubConfiguration->getFactoryConfig();
                GetFactorySettingsResponse response;

                response.firmwareVersion = (KOMAHUB_FIRMWARE_VERSION_MAJOR << 8) + KOMAHUB_FIRMWARE_VERSION_MINOR;
                response.serialNumber = factoryConfig.serial;
                response.fuseDelay = factoryConfig.fuseDelay;
                response.skyQualityOffset = factoryConfig.skyQualityOffset;
                response.features = (uint8_t)(
                    (factoryConfig.features.tempprobes ? (1 << 0) : 0) +
                    (factoryConfig.features.skyquality ? (1 << 1) : 0) +
                    (factoryConfig.features.ambientpth ? (1 << 2) : 0) +
                    (factoryConfig.features.skytemp ? (1 << 3) : 0));
                response.boardRevision = factoryConfig.boardRevision;

                memcpy(usbSendBuffer, &response, sizeof(GetFactorySettingsResponse));
                RawHID.send(usbSendBuffer, 1000);
                break;
            }

            case GETOUTPUTSETTINGS: {
                GetOutputSettingsCommand* cmd = (GetOutputSettingsCommand*)&data[pos];
                GetOutputSettingsResponse response;

                const HubConfiguration::OutputSettings& outputSettings = hubConfiguration->getOutputSettings();
                const HubConfiguration::Output& output = outputSettings.outputs[cmd->outputNumber];
                memcpy(&response.name, output.name, 16);
                response.fuseCurrent = output.fuseCurrent;
                response.type = output.type.type;

                memcpy(usbSendBuffer, &response, sizeof(GetOutputSettingsResponse));
                RawHID.send(usbSendBuffer, 1000);
                pos += sizeof(GetOutputSettingsCommand);
                break;
            }

            case GETSTATUS: {
                GetStatusResponse response;

                const HubConfiguration::State& state = hubConfiguration->getState();
                response.relayIsOpenBits = state.relayIsOpenBits;
                response.fuseIsBlownBits = state.fuseIsBlownBits;
                for (int i = 0; i < 6; i++) {
                    response.pwmPercentages[i] = state.pwmPercentages[i];
                }
                // input voltage
                response.inputVoltage = (uint8_t)roundf(VoltageMonitor::getInputVoltage() * 10);
                // output power, amps
                for (int i = 0; i < 6; i++) {
                    response.outputPower[i] = (uint8_t)roundf(PowerOutputs::getOutputPower(i) * 10);
                }
                // temperatures
                response.numberOfTemperatureProbes = TemperatureSensors::getNumberOfSensors();
                for (int i = 0; i < 4; i++) {
                    response.temperatureProbes[i] = TemperatureSensors::getCurrentTemperatureValues()[i] * 10;
                }
                // weather
                response.temperature = Weather::getTemperature();
                response.humidity = Weather::getHumidity();
                response.pressure = Weather::getPressure();
                response.dewpoint = Weather::getDewPoint();
                // SkyQuality
                response.skyquality = SkyQuality::getSkyQuality();

                memcpy(usbSendBuffer, &response, sizeof(GetStatusResponse));
                RawHID.send(usbSendBuffer, 1000);
                break;
            }

            case GETRAWPOWERUSAGE: {
                GetRawPowerUsageResponse response;
                memcpy(&response.rawValues, AnalogInput::getAverageValues(), 8*sizeof(uint16_t));
                memcpy(usbSendBuffer, &response, sizeof(GetRawPowerUsageResponse));
                RawHID.send(usbSendBuffer, 1000);
                break;
            }

            case FACTORYRESET: {
                FactoryResetCommand* cmd = (FactoryResetCommand*)&data[pos];
                USB::hubConfiguration->factoryReset(cmd->serial, cmd->r6ohms, cmd->r7ohms, cmd->boardRevision);
                pos += sizeof(FactoryResetCommand);
                break;
            }

            case REBOOT_BOOTLOADER: {
                cli();
                // disable watchdog, if enabled
                // disable all peripherals
                UDCON = 1;
                UCSR1B = 0;
                delay(5);
                EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
                TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
                DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
                PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
                asm volatile("jmp 0x7000");
                break;
            }

            case SETRELAY: {
                SetRelayCommand* cmd = (SetRelayCommand*)&data[pos];
                if (cmd->enabled) {
                    hubConfiguration->getState().relayIsOpenBits |= (1 << cmd->outputNumber);
                } else {
                    hubConfiguration->getState().relayIsOpenBits &= ~(1 << cmd->outputNumber);
                }
                hubConfiguration->saveState();
                pos += sizeof(SetRelayCommand);
                break;
            }

            case SETPWMDUTY: {
                SetPwmDutyCommand* cmd = (SetPwmDutyCommand*)&data[pos];
                hubConfiguration->getState().pwmPercentages[cmd->outputNumber] = cmd->duty;
                hubConfiguration->saveState();
                pos += sizeof(SetPwmDutyCommand);
                break;
            }

            case RESETFUSE: {
                ResetFuseCommand* cmd = (ResetFuseCommand*)&data[pos];
                hubConfiguration->getState().fuseIsBlownBits &= ~(1 << cmd->outputNumber);
                hubConfiguration->getState().relayIsOpenBits &= ~(1 << cmd->outputNumber);
                hubConfiguration->saveState();
                pos += sizeof(ResetFuseCommand);
                break;
            }

            case CONFIGUREOUTPUT: {
                HubConfiguration::OutputSettings& outputSettings = hubConfiguration->getOutputSettings();

                ConfigureOutputCommand* cmd = (ConfigureOutputCommand*)&data[pos];
                outputSettings.outputs[cmd->outputNumber].type.type = cmd->outputType;
                outputSettings.outputs[cmd->outputNumber].fuseCurrent = cmd->fuseCurrent;
                memcpy(outputSettings.outputs[cmd->outputNumber].name, cmd->name, 16);
                hubConfiguration->saveOutputConfiguration();
                pos += sizeof(ConfigureOutputCommand);
                break;
            }

            case CONFIGURESETTINGS: {
                HubConfiguration::FactoryConfig& factoryConfig = hubConfiguration->getFactoryConfig();

                ConfigureSettingsCommand* cmd = (ConfigureSettingsCommand*)&data[pos];
                factoryConfig.fuseDelay = cmd->fuseDelay;
                factoryConfig.skyQualityOffset = cmd->skyQualityOffset;

                if (factoryConfig.features.skyquality && !cmd->featureSkyQuality)
                    SkyQuality::stop();
                if (!factoryConfig.features.tempprobes && cmd->featureTempProbe)
                    TemperatureSensors::init(hubConfiguration);
                if (!factoryConfig.features.skyquality && cmd->featureSkyQuality)
                    SkyQuality::init(hubConfiguration);
                if (!factoryConfig.features.skytemp && cmd->featureSkyTemperature)
                    SkyTemperature::init(hubConfiguration);
                if (!factoryConfig.features.ambientpth && cmd->featureAmbientPTH)
                    Weather::init(hubConfiguration);

                factoryConfig.features.tempprobes = cmd->featureTempProbe;
                factoryConfig.features.skyquality = cmd->featureSkyQuality;
                factoryConfig.features.ambientpth = cmd->featureAmbientPTH;
                factoryConfig.features.skytemp = cmd->featureSkyTemperature;
                hubConfiguration->saveFactoryConfig();

                pos += sizeof(ConfigureSettingsCommand);
                break;
            }

            case CALIBRATEOUTPUT: {
                HubConfiguration::OutputSettings& outputSettings = hubConfiguration->getOutputSettings();

                CalibrateOutputCommand* cmd = (CalibrateOutputCommand*)&data[pos];
                outputSettings.outputs[cmd->outputNumber].coeffs.a = cmd->a;
                outputSettings.outputs[cmd->outputNumber].coeffs.b = cmd->b;
                outputSettings.outputs[cmd->outputNumber].coeffs.c = cmd->c;
                hubConfiguration->saveOutputConfiguration();
                pos += sizeof(ConfigureOutputCommand);
                break;
            }
        }
    }
}

void USB::handlePacket(uint8_t* buffer) {
    uint8_t identifier = buffer[0];
    unsigned int len = buffer[1];
    uint8_t* data = &buffer[2];
    if (identifier != 'K' ||
        len >= 62) {
        return;
    }

    handleCommands(data, len);
}

void USB::init(HubConfiguration* hubConfiguration) {
    USB::hubConfiguration = hubConfiguration;
}

#endif
<commit_msg>Scale temperature values properly<commit_after>/*
 * Copyright (c) 2016 Jari Saukkonen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <Arduino.h>

#ifdef CORE_TEENSY_RAWHID

#include "AnalogInput.h"
#include "HubConfiguration.h"
#include "PowerOutputs.h"
#include "SkyQuality.h"
#include "SkyTemperature.h"
#include "TemperatureSensors.h"
#include "USB.h"
#include "USBCommands.h"
#include "Weather.h"
#include "Version.h"
#include "VoltageMonitor.h"

static uint8_t usbSendBuffer[64];
static uint8_t usbRecvBuffer[64];

HubConfiguration* USB::hubConfiguration;

void USB::loop() {
    int available = RawHID.available();
    if (available > 0) {
        memset(usbSendBuffer, 0, 64);
        RawHID.recv(usbRecvBuffer, available);
        handleCommands(usbRecvBuffer, available);
    }
}

void USB::handleCommands(uint8_t* data, unsigned int maxlen) {
    unsigned int pos = 0;
    if (data[pos++] != 'K')
        return;

    while (pos < maxlen) {
        uint8_t command = data[pos++];
        switch (command) {
            case END: {
                return;
            }

            case GETFACTORYSETTINGS: {
                const HubConfiguration::FactoryConfig& factoryConfig = hubConfiguration->getFactoryConfig();
                GetFactorySettingsResponse response;

                response.firmwareVersion = (KOMAHUB_FIRMWARE_VERSION_MAJOR << 8) + KOMAHUB_FIRMWARE_VERSION_MINOR;
                response.serialNumber = factoryConfig.serial;
                response.fuseDelay = factoryConfig.fuseDelay;
                response.skyQualityOffset = factoryConfig.skyQualityOffset;
                response.features = (uint8_t)(
                    (factoryConfig.features.tempprobes ? (1 << 0) : 0) +
                    (factoryConfig.features.skyquality ? (1 << 1) : 0) +
                    (factoryConfig.features.ambientpth ? (1 << 2) : 0) +
                    (factoryConfig.features.skytemp ? (1 << 3) : 0));
                response.boardRevision = factoryConfig.boardRevision;

                memcpy(usbSendBuffer, &response, sizeof(GetFactorySettingsResponse));
                RawHID.send(usbSendBuffer, 1000);
                break;
            }

            case GETOUTPUTSETTINGS: {
                GetOutputSettingsCommand* cmd = (GetOutputSettingsCommand*)&data[pos];
                GetOutputSettingsResponse response;

                const HubConfiguration::OutputSettings& outputSettings = hubConfiguration->getOutputSettings();
                const HubConfiguration::Output& output = outputSettings.outputs[cmd->outputNumber];
                memcpy(&response.name, output.name, 16);
                response.fuseCurrent = output.fuseCurrent;
                response.type = output.type.type;

                memcpy(usbSendBuffer, &response, sizeof(GetOutputSettingsResponse));
                RawHID.send(usbSendBuffer, 1000);
                pos += sizeof(GetOutputSettingsCommand);
                break;
            }

            case GETSTATUS: {
                GetStatusResponse response;

                const HubConfiguration::State& state = hubConfiguration->getState();
                response.relayIsOpenBits = state.relayIsOpenBits;
                response.fuseIsBlownBits = state.fuseIsBlownBits;
                for (int i = 0; i < 6; i++) {
                    response.pwmPercentages[i] = state.pwmPercentages[i];
                }
                // input voltage
                response.inputVoltage = (uint8_t)roundf(VoltageMonitor::getInputVoltage() * 10);
                // output power, amps
                for (int i = 0; i < 6; i++) {
                    response.outputPower[i] = (uint8_t)roundf(PowerOutputs::getOutputPower(i) * 10);
                }
                // temperatures
                response.numberOfTemperatureProbes = TemperatureSensors::getNumberOfSensors();
                for (int i = 0; i < 4; i++) {
                    response.temperatureProbes[i] = TemperatureSensors::getCurrentTemperatureValues()[i] * 10;
                }
                // weather
                response.temperature = Weather::getTemperature() * 10;
                response.humidity = Weather::getHumidity();
                response.pressure = Weather::getPressure() * 10;
                response.dewpoint = Weather::getDewPoint() * 10;
                // SkyQuality
                response.skyquality = SkyQuality::getSkyQuality() * 10;

                memcpy(usbSendBuffer, &response, sizeof(GetStatusResponse));
                RawHID.send(usbSendBuffer, 1000);
                break;
            }

            case GETRAWPOWERUSAGE: {
                GetRawPowerUsageResponse response;
                memcpy(&response.rawValues, AnalogInput::getAverageValues(), 8*sizeof(uint16_t));
                memcpy(usbSendBuffer, &response, sizeof(GetRawPowerUsageResponse));
                RawHID.send(usbSendBuffer, 1000);
                break;
            }

            case FACTORYRESET: {
                FactoryResetCommand* cmd = (FactoryResetCommand*)&data[pos];
                USB::hubConfiguration->factoryReset(cmd->serial, cmd->r6ohms, cmd->r7ohms, cmd->boardRevision);
                pos += sizeof(FactoryResetCommand);
                break;
            }

            case REBOOT_BOOTLOADER: {
                cli();
                // disable watchdog, if enabled
                // disable all peripherals
                UDCON = 1;
                UCSR1B = 0;
                delay(5);
                EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
                TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
                DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
                PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
                asm volatile("jmp 0x7000");
                break;
            }

            case SETRELAY: {
                SetRelayCommand* cmd = (SetRelayCommand*)&data[pos];
                if (cmd->enabled) {
                    hubConfiguration->getState().relayIsOpenBits |= (1 << cmd->outputNumber);
                } else {
                    hubConfiguration->getState().relayIsOpenBits &= ~(1 << cmd->outputNumber);
                }
                hubConfiguration->saveState();
                pos += sizeof(SetRelayCommand);
                break;
            }

            case SETPWMDUTY: {
                SetPwmDutyCommand* cmd = (SetPwmDutyCommand*)&data[pos];
                hubConfiguration->getState().pwmPercentages[cmd->outputNumber] = cmd->duty;
                hubConfiguration->saveState();
                pos += sizeof(SetPwmDutyCommand);
                break;
            }

            case RESETFUSE: {
                ResetFuseCommand* cmd = (ResetFuseCommand*)&data[pos];
                hubConfiguration->getState().fuseIsBlownBits &= ~(1 << cmd->outputNumber);
                hubConfiguration->getState().relayIsOpenBits &= ~(1 << cmd->outputNumber);
                hubConfiguration->saveState();
                pos += sizeof(ResetFuseCommand);
                break;
            }

            case CONFIGUREOUTPUT: {
                HubConfiguration::OutputSettings& outputSettings = hubConfiguration->getOutputSettings();

                ConfigureOutputCommand* cmd = (ConfigureOutputCommand*)&data[pos];
                outputSettings.outputs[cmd->outputNumber].type.type = cmd->outputType;
                outputSettings.outputs[cmd->outputNumber].fuseCurrent = cmd->fuseCurrent;
                memcpy(outputSettings.outputs[cmd->outputNumber].name, cmd->name, 16);
                hubConfiguration->saveOutputConfiguration();
                pos += sizeof(ConfigureOutputCommand);
                break;
            }

            case CONFIGURESETTINGS: {
                HubConfiguration::FactoryConfig& factoryConfig = hubConfiguration->getFactoryConfig();

                ConfigureSettingsCommand* cmd = (ConfigureSettingsCommand*)&data[pos];
                factoryConfig.fuseDelay = cmd->fuseDelay;
                factoryConfig.skyQualityOffset = cmd->skyQualityOffset;

                if (factoryConfig.features.skyquality && !cmd->featureSkyQuality)
                    SkyQuality::stop();
                if (!factoryConfig.features.tempprobes && cmd->featureTempProbe)
                    TemperatureSensors::init(hubConfiguration);
                if (!factoryConfig.features.skyquality && cmd->featureSkyQuality)
                    SkyQuality::init(hubConfiguration);
                if (!factoryConfig.features.skytemp && cmd->featureSkyTemperature)
                    SkyTemperature::init(hubConfiguration);
                if (!factoryConfig.features.ambientpth && cmd->featureAmbientPTH)
                    Weather::init(hubConfiguration);

                factoryConfig.features.tempprobes = cmd->featureTempProbe;
                factoryConfig.features.skyquality = cmd->featureSkyQuality;
                factoryConfig.features.ambientpth = cmd->featureAmbientPTH;
                factoryConfig.features.skytemp = cmd->featureSkyTemperature;
                hubConfiguration->saveFactoryConfig();

                pos += sizeof(ConfigureSettingsCommand);
                break;
            }

            case CALIBRATEOUTPUT: {
                HubConfiguration::OutputSettings& outputSettings = hubConfiguration->getOutputSettings();

                CalibrateOutputCommand* cmd = (CalibrateOutputCommand*)&data[pos];
                outputSettings.outputs[cmd->outputNumber].coeffs.a = cmd->a;
                outputSettings.outputs[cmd->outputNumber].coeffs.b = cmd->b;
                outputSettings.outputs[cmd->outputNumber].coeffs.c = cmd->c;
                hubConfiguration->saveOutputConfiguration();
                pos += sizeof(ConfigureOutputCommand);
                break;
            }
        }
    }
}

void USB::handlePacket(uint8_t* buffer) {
    uint8_t identifier = buffer[0];
    unsigned int len = buffer[1];
    uint8_t* data = &buffer[2];
    if (identifier != 'K' ||
        len >= 62) {
        return;
    }

    handleCommands(data, len);
}

void USB::init(HubConfiguration* hubConfiguration) {
    USB::hubConfiguration = hubConfiguration;
}

#endif
<|endoftext|>