<commit_before>#include "CryFuse.h"

#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <cassert>

#include "cryfs_lib/CryNode.h"
#include "cryfs_lib/CryErrnoException.h"

#define UNUSED(expr) (void)(expr)

using fusepp::path;

namespace cryfs {

namespace {
  int errcode_map(int exit_status) {
    if (exit_status < 0) {
      return -errno;
    }
    return exit_status;
  }
}

CryFuse::CryFuse(CryDevice *device)
  :_device(device) {
}

int CryFuse::getattr(const path &path, struct stat *stbuf) {
  try {
    _device->lstat(path, stbuf);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) {
  //printf("fgetattr(%s, _, _)\n", path.c_str());

  // On FreeBSD, trying to do anything with the mountpoint ends up
  // opening it, and then using the FD for an fgetattr.  So in the
  // special case of a path of "/", I need to do a getattr on the
  // underlying root directory instead of doing the fgetattr().
  // TODO Check if necessary
  if (path.native() == "/") {
    return getattr(path, stbuf);
  }

  try {
	_device->fstat(fileinfo->fh, stbuf);
	return 0;
  } catch(cryfs::CryErrnoException &e) {
	  return -e.getErrno();
  }
}

//TODO
int CryFuse::readlink(const path &path, char *buf, size_t size) {
  //printf("readlink(%s, _, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size,
  //but the posix version does not and also doesn't append one.
  int real_size = ::readlink(real_path.c_str(), buf, size-1);
  if (real_size < 0) {
    return -errno;
  }
  //Terminate the string
  buf[real_size] = '\0';

  return 0;
}

int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) {
  UNUSED(rdev);
  UNUSED(mode);
  UNUSED(path);
  printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode);
  return 0;
}

int CryFuse::mkdir(const path &path, mode_t mode) {
  //printf("mkdir(%s, %d)\n", path.c_str(), mode);
  try {
    _device->mkdir(path, mode);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::unlink(const path &path) {
  //printf("unlink(%s)\n", path.c_str());
  try {
    _device->unlink(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::rmdir(const path &path) {
  try {
    _device->rmdir(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::symlink(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: symlink(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::symlink(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::rename(const path &from, const path &to) {
  //printf("rename(%s, %s)\n", from.c_str(), to.c_str());
  try {
    _device->rename(from, to);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::link(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: link(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::link(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chmod(const path &path, mode_t mode) {
  printf("NOT IMPLEMENTED: chmod(%s, %d)\n", path.c_str(), mode);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chmod(real_path.c_str(), mode);
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chown(const path &path, uid_t uid, gid_t gid) {
  printf("NOT IMPLEMENTED: chown(%s, %d, %d)\n", path.c_str(), uid, gid);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chown(real_path.c_str(), uid, gid);
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::truncate(const path &path, off_t size) {
  //printf("truncate(%s, %zu)\n", path.c_str(), size);
  try {
    _device->truncate(path, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) {
  //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size);
	UNUSED(path);
  try {
    _device->ftruncate(fileinfo->fh, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::utimens(const path &path, const timespec times[2]) {
  UNUSED(times);
  printf("NOT IMPLEMENTED: utimens(%s, _)\n", path.c_str());
  //auto real_path = _device->RootDir() / path;
  //struct timeval tv[2];
  //tv[0].tv_sec = times[0].tv_sec;
  //tv[0].tv_usec = times[0].tv_nsec / 1000;
  //tv[1].tv_sec = times[1].tv_sec;
  //tv[1].tv_usec = times[1].tv_nsec / 1000;
  //int retstat = ::lutimes(real_path.c_str(), tv);
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::open(const path &path, fuse_file_info *fileinfo) {
  //printf("open(%s, _)\n", path.c_str());
  try {
	  fileinfo->fh = _device->openFile(path, fileinfo->flags);
	  return 0;
  } catch (CryErrnoException &e) {
	  return -e.getErrno();
  }
}

int CryFuse::release(const path &path, fuse_file_info *fileinfo) {
  //printf("release(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
	  _device->closeFile(fileinfo->fh);
	  return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    //printf("Reading from file %d\n", fileinfo->fh);
    //fflush(stdout);
    return _device->read(fileinfo->fh, buf, size, offset);
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    _device->write(fileinfo->fh, buf, size, offset);
    return size;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::statfs(const path &path, struct statvfs *fsstat) {
  printf("HALF-IMPLEMENTED: statfs(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::statvfs(real_path.c_str(), fsstat);
  return errcode_map(retstat);
}

//TODO
int CryFuse::flush(const path &path, fuse_file_info *fileinfo) {
  //printf("Called non-implemented flush(%s, _)\n", path.c_str());
  UNUSED(path);
  UNUSED(fileinfo);
  return 0;
}

int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) {
  //printf("fsync(%s, %d, _)\n", path.c_str(), datasync);
  UNUSED(path);
  try {
    if (datasync) {
      _device->fdatasync(fileinfo->fh);
    } else {
      _device->fsync(fileinfo->fh);
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) {
  //printf("opendir(%s, _)\n", path.c_str());
  try {
    fileinfo->fh = _device->openDir(path);
    return 0;
  } catch(CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) {
  UNUSED(path);
  //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset);
  UNUSED(offset);
  try {
    auto entries = _device->readDir(fileinfo->fh);
    for (const auto &entry : *entries) {
      //TODO Also give file attributes (third param of filler)
      if (filler(buf, entry.c_str(), nullptr, 0) != 0) {
        return -ENOMEM;
      }
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) {
  //printf("releasedir(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
    _device->closeDir(fileinfo->fh);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) {
  UNUSED(fileinfo);
  UNUSED(datasync);
  UNUSED(path);
  //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync);
  return 0;
}

void CryFuse::init(fuse_conn_info *conn) {
  UNUSED(conn);
  //printf("init()\n");
}

void CryFuse::destroy() {
  //printf("destroy()\n");
}

int CryFuse::access(const path &path, int mask) {
  //printf("access(%s, %d)\n", path.c_str(), mask);
  try {
    _device->access(path, mask);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) {
  //printf("create(%s, %d, _)\n", path.c_str(), mode);
  try {
    fileinfo->fh = _device->createAndOpenFile(path, mode);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

} /* namespace cryfs */
<commit_msg>Fix unimplemented utimens<commit_after>#include "CryFuse.h"

#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <cassert>

#include "cryfs_lib/CryNode.h"
#include "cryfs_lib/CryErrnoException.h"

#define UNUSED(expr) (void)(expr)

using fusepp::path;

namespace cryfs {

namespace {
  int errcode_map(int exit_status) {
    if (exit_status < 0) {
      return -errno;
    }
    return exit_status;
  }
}

CryFuse::CryFuse(CryDevice *device)
  :_device(device) {
}

int CryFuse::getattr(const path &path, struct stat *stbuf) {
  try {
    _device->lstat(path, stbuf);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) {
  //printf("fgetattr(%s, _, _)\n", path.c_str());

  // On FreeBSD, trying to do anything with the mountpoint ends up
  // opening it, and then using the FD for an fgetattr.  So in the
  // special case of a path of "/", I need to do a getattr on the
  // underlying root directory instead of doing the fgetattr().
  // TODO Check if necessary
  if (path.native() == "/") {
    return getattr(path, stbuf);
  }

  try {
	_device->fstat(fileinfo->fh, stbuf);
	return 0;
  } catch(cryfs::CryErrnoException &e) {
	  return -e.getErrno();
  }
}

//TODO
int CryFuse::readlink(const path &path, char *buf, size_t size) {
  //printf("readlink(%s, _, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size,
  //but the posix version does not and also doesn't append one.
  int real_size = ::readlink(real_path.c_str(), buf, size-1);
  if (real_size < 0) {
    return -errno;
  }
  //Terminate the string
  buf[real_size] = '\0';

  return 0;
}

int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) {
  UNUSED(rdev);
  UNUSED(mode);
  UNUSED(path);
  printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode);
  return 0;
}

int CryFuse::mkdir(const path &path, mode_t mode) {
  //printf("mkdir(%s, %d)\n", path.c_str(), mode);
  try {
    _device->mkdir(path, mode);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::unlink(const path &path) {
  //printf("unlink(%s)\n", path.c_str());
  try {
    _device->unlink(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::rmdir(const path &path) {
  try {
    _device->rmdir(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::symlink(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: symlink(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::symlink(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::rename(const path &from, const path &to) {
  //printf("rename(%s, %s)\n", from.c_str(), to.c_str());
  try {
    _device->rename(from, to);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::link(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: link(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::link(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chmod(const path &path, mode_t mode) {
  printf("NOT IMPLEMENTED: chmod(%s, %d)\n", path.c_str(), mode);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chmod(real_path.c_str(), mode);
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chown(const path &path, uid_t uid, gid_t gid) {
  printf("NOT IMPLEMENTED: chown(%s, %d, %d)\n", path.c_str(), uid, gid);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chown(real_path.c_str(), uid, gid);
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::truncate(const path &path, off_t size) {
  //printf("truncate(%s, %zu)\n", path.c_str(), size);
  try {
    _device->truncate(path, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) {
  //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size);
	UNUSED(path);
  try {
    _device->ftruncate(fileinfo->fh, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::utimens(const path &path, const timespec times[2]) {
  UNUSED(times);
  printf("NOT IMPLEMENTED: utimens(%s, _)\n", path.c_str());
  //auto real_path = _device->RootDir() / path;
  //struct timeval tv[2];
  //tv[0].tv_sec = times[0].tv_sec;
  //tv[0].tv_usec = times[0].tv_nsec / 1000;
  //tv[1].tv_sec = times[1].tv_sec;
  //tv[1].tv_usec = times[1].tv_nsec / 1000;
  //int retstat = ::lutimes(real_path.c_str(), tv);
  //return errcode_map(retstat);
  return 0;
}

int CryFuse::open(const path &path, fuse_file_info *fileinfo) {
  //printf("open(%s, _)\n", path.c_str());
  try {
	  fileinfo->fh = _device->openFile(path, fileinfo->flags);
	  return 0;
  } catch (CryErrnoException &e) {
	  return -e.getErrno();
  }
}

int CryFuse::release(const path &path, fuse_file_info *fileinfo) {
  //printf("release(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
	  _device->closeFile(fileinfo->fh);
	  return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    //printf("Reading from file %d\n", fileinfo->fh);
    //fflush(stdout);
    return _device->read(fileinfo->fh, buf, size, offset);
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    _device->write(fileinfo->fh, buf, size, offset);
    return size;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::statfs(const path &path, struct statvfs *fsstat) {
  printf("HALF-IMPLEMENTED: statfs(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::statvfs(real_path.c_str(), fsstat);
  return errcode_map(retstat);
}

//TODO
int CryFuse::flush(const path &path, fuse_file_info *fileinfo) {
  //printf("Called non-implemented flush(%s, _)\n", path.c_str());
  UNUSED(path);
  UNUSED(fileinfo);
  return 0;
}

int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) {
  //printf("fsync(%s, %d, _)\n", path.c_str(), datasync);
  UNUSED(path);
  try {
    if (datasync) {
      _device->fdatasync(fileinfo->fh);
    } else {
      _device->fsync(fileinfo->fh);
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) {
  //printf("opendir(%s, _)\n", path.c_str());
  try {
    fileinfo->fh = _device->openDir(path);
    return 0;
  } catch(CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) {
  UNUSED(path);
  //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset);
  UNUSED(offset);
  try {
    auto entries = _device->readDir(fileinfo->fh);
    for (const auto &entry : *entries) {
      //TODO Also give file attributes (third param of filler)
      if (filler(buf, entry.c_str(), nullptr, 0) != 0) {
        return -ENOMEM;
      }
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) {
  //printf("releasedir(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
    _device->closeDir(fileinfo->fh);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) {
  UNUSED(fileinfo);
  UNUSED(datasync);
  UNUSED(path);
  //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync);
  return 0;
}

void CryFuse::init(fuse_conn_info *conn) {
  UNUSED(conn);
  //printf("init()\n");
}

void CryFuse::destroy() {
  //printf("destroy()\n");
}

int CryFuse::access(const path &path, int mask) {
  //printf("access(%s, %d)\n", path.c_str(), mask);
  try {
    _device->access(path, mask);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) {
  //printf("create(%s, %d, _)\n", path.c_str(), mode);
  try {
    fileinfo->fh = _device->createAndOpenFile(path, mode);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

} /* namespace cryfs */
<|endoftext|>


<commit_before>/* $Id: CreateCuts.C,v 1.5 2008/01/11 08:28:52 jgrosseo Exp $ */

// this macro creates the track and event cuts used in this analysis

AliESDtrackCuts* CreateTrackCuts(AliPWG0Helper::AnalysisMode analysisMode, Bool_t hists = kTRUE)
{
  AliESDtrackCuts* esdTrackCuts = new AliESDtrackCuts("AliESDtrackCuts");

  if (hists)
    esdTrackCuts->DefineHistograms(1);

  // default cuts for ITS+TPC
  Double_t cov1 = 2;
  Double_t cov2 = 2;
  Double_t cov3 = 0.5;
  Double_t cov4 = 0.5;
  Double_t cov5 = 2;
  Double_t nSigma = 4;

  Bool_t tpcRefit = kTRUE;
  Bool_t sigmaToVertex = kTRUE;

  TString tag("Global tracking");

  // TPC-only cuts
  if (analysisMode & AliPWG0Helper::kTPC)
  {
    cov1 = 1e10;
    cov2 = 1e10;
    cov3 = 1e10;
    cov4 = 1e10;
    cov5 = 1e10;

    tpcRefit = kFALSE;
    sigmaToVertex = kFALSE;

    tag = "TPC-only tracking";
  }

  // cuts for data without field
  if (!(analysisMode & AliPWG0Helper::kFieldOn))
  {
    cov5 = 1e10;
    tag += " without field";
  }

  esdTrackCuts->SetMaxCovDiagonalElements(cov1, cov2, cov3, cov4, cov5);

  esdTrackCuts->SetRequireSigmaToVertex(sigmaToVertex);

  if (sigmaToVertex) {
    esdTrackCuts->SetMaxNsigmaToVertex(nSigma);
  }
  else
  {
    esdTrackCuts->SetMaxDCAToVertexZ(3.2);
    esdTrackCuts->SetMaxDCAToVertexXY(2.4);
    esdTrackCuts->SetDCAToVertex2D(kTRUE);
  }

  esdTrackCuts->SetRequireTPCRefit(tpcRefit);
  esdTrackCuts->SetAcceptKinkDaughters(kFALSE);

  esdTrackCuts->SetMinNClustersTPC(50);
  esdTrackCuts->SetMaxChi2PerClusterTPC(4);

  Printf("Created track cuts for: %s", tag.Data());

  return esdTrackCuts;
}

<commit_msg>updated TPC cuts<commit_after>/* $Id: CreateCuts.C,v 1.5 2008/01/11 08:28:52 jgrosseo Exp $ */

// this macro creates the track cuts used in this analysis

AliESDtrackCuts* CreateTrackCuts(AliPWG0Helper::AnalysisMode analysisMode, Bool_t hists = kTRUE)
{
  AliESDtrackCuts* esdTrackCuts = 0;

  // see https://twiki.cern.ch/twiki/bin/view/ALICE/SelectionOfPrimaryTracksForPp2009DataAnalysis

  if (analysisMode & AliPWG0Helper::kTPC)
  {
    esdTrackCuts = new AliESDtrackCuts("AliESDtrackCuts");

    TString tag("TPC-only tracking");

    esdTrackCuts->SetMaxDCAToVertexZ(3.2);
    esdTrackCuts->SetMaxDCAToVertexXY(2.4);
    esdTrackCuts->SetDCAToVertex2D(kTRUE);

    esdTrackCuts->SetRequireTPCRefit(kTRUE);
    esdTrackCuts->SetAcceptKinkDaughters(kFALSE);
    esdTrackCuts->SetMinNClustersTPC(70);
    esdTrackCuts->SetMaxChi2PerClusterTPC(4);
  }

  if (analysisMode & AliPWG0Helper::kTPCITS)
  {
    esdTrackCuts = AliESDtrackCuts::GetStandardITSTPCTrackCuts2009(kTRUE);

    TString tag("Global tracking");
  }

  if (hists)
    esdTrackCuts->DefineHistograms(1);

  // cuts for data without field
  if (!(analysisMode & AliPWG0Helper::kFieldOn))
  {
    tag += " without field";
  }

  Printf("Created track cuts for: %s", tag.Data());

  return esdTrackCuts;
}

<|endoftext|>


<commit_before>#pragma once

/* Voxel test with procedural data. */

#include "material.hpp"

#include "math/vector3.hpp"
#include <cmath>

#include <cstdint>

#include <cstddef>

#include <algorithm>

#include "contact.hpp"

#include "geometry/voxel_types.hpp"

#include "geometry/fast_stack.hpp"

#include "geometry/aabb.hpp"

// the encoding currently used for voxels imposes a maximum of 2 billion nodes
// but it may make sense to use uint64_t and use the extra 32 bits in the leaf
// nodes for fast-changing material properties (or other)
// (we'd need to know how many voxels constitute a typical world with LOD, and
//  see if double the memory usage is worth a richer & faster material system)

struct Node
{
    uint32_t child[8];
};

uint32_t encode_leaf(const uint16_t &normal, const uint16_t &material)
{
    return (((material & 0x7FFF) << 16) | normal) | 0x80000000;
}

// assumes the high bit marker has already been removed
void decode_leaf(const uint32_t &leaf, uint16_t &normal, uint16_t &material)
{
    material = leaf >> 16;
    normal = leaf & 0xFFFF;
}

#define svo_depth 9 // TEMPORARY (will not be hardcoded later)

#define STACK_SIZE (4 * svo_depth) // can probably bring this down with some mathematical analysis of worst-case SVO traversal
                                   // (until we figure out how stackless traversal works, anyway)
                                   // (it doesn't really matter on the CPU due to how the stack works, but will be a killer on
                                   // the GPU as it will increase register pressure and kill parallelism ---> need stackless)

static distance3 light_pos = distance3(0.2f, -0.35f, 0.3f);

class VoxelTest
{
public:
    distance3 light() const
    {
        return light_pos;
    }

    bool intersects(const distance3 &origin, const distance3 &direction,
		            distance &dist, Contact &contact) const
	{
        return traverse(origin, direction,
                        std::numeric_limits<distance>::infinity(), dist, contact, false);
	}

    bool occludes(const distance3 &origin, const distance3 &direction,
                  distance &dist, distance target_dist) const
    {
        Contact contact;

        return traverse(origin, direction,
                        target_dist, dist, contact, true);
    }

    bool occludes(const distance3 &origin, const distance3 &direction,
                  distance target_dist) const
    {
        distance dist;
        Contact contact;

        return traverse(origin, direction,
                        target_dist, dist, contact, true);
    }

    bool occludes(const distance3 &origin, const distance3 &direction) const
    {
        return occludes(origin, direction, std::numeric_limits<distance>::infinity());
    }

	VoxelTest()
	{
	    printf("Building SVO (this is done only once).\n");
	    init_mem();
	    root = build_SVO(svo_depth, world);
	    printf("SVO built (%zu nodes, depth = %d).\n",
	           node_offset, svo_depth);
	}

private:
    const aabb world = aabb{distance3(-1, -1, -1), distance3(1, 1, 1)};

    // looks up a voxel through its memory address (this could be an offset later on
    // for virtualization) and fills in an appropriate Contact structure to indicate
    // the material and surface normal, when applicable

    // this function has some pretty strong invariants to maintain, pay attention.
    // (read: if the invariants are not maintained, traversal will FAIL horribly)

    // (procedural data generation can happen here as well)
    inline
    bool lookup(const  distance3 &origin, const distance3 &direction,
                const stack_item   &leaf,       distance    &nearest,
                                                    Contact &contact) const
    {
        // default implementation, voxels are cubic and solid

        (void)origin;
        (void)direction;

        decode_leaf(leaf.offset, contact.normal, contact.material);

        nearest = leaf.hit; // IMPORTANT: you must set "nearest" to the
        // nearest intersection within the voxel's bounding box, IF AND
        // ONLY IF this intersection is closer than the currently recorded
        // "nearest" value (and if this is the case, populate "contact",
        // else LEAVE IT ALONE).

        return true; // return if and only if "nearest" was modified
    } __attribute__ ((hot))

    // this is the heart of the voxel renderer, the SVO traversal code
    // this is where optimization efforts should be focused
    // current optimizations and todo's:
    // DONE: convert to iteration and use a stack
    // TODO: implement and benchmark stackless traversal algorithms
    // DONE: uses early rejection by sorting children
    // DONE: fix remaining bugs

    // CURRENT REASONS FOR BEING SLOW:
    // 1. no SSE vector instructions  [WIP]
    // 2. unnecessary ray_aabb call in leaf [fixed]
    // 3. recursion [fixed]
    // 4. "intersections" buffer not optimized [fixed]
    // 5. tree nodes allocated via malloc(), poor locality [fixed]
    // 6. ray_aabb is not optimized at all  [fixed]
    // 7. possible algorithmic improvements?

    // QUESTIONS TO RESOLVE:
    // 1. do we need "far" in the "intersections" buffer? [NO]
    // 2. are there any bugs? need a known voxel data set to test against
    //    (do that once we have interactivity, to better locate glitches)

    // ADDITIONAL INFO:
    // - final tree will potentially be very deep, with up to 64 levels
    //   (32 levels --> 64km^3 with 0.015 mm resolution)
    // - procedural data generation can be done outside the tree, once
    //   a voxel is intersected, by generating procedural data *inside*
    //   the intersected voxel, depending on its material
    //   (this is actually a REALLY GOOD idea as it completely gets rid
    //    of any cubic artifacts and improves subpixel performance)
    // - 64 levels --> 1800 AU^3 with 0.015 mm resolution
    //   (that's 274 billion km^3, I trust this will be enough)
    // - possibly use a hybrid approach, with two trees, one handling large
    //   64km^3 "chunks", optimized for ultra fast traversal, and another
    //   which focuses on culling chunks to improve performance
    bool traverse(const distance3 &origin, const distance3 &direction,
                  const distance   &range,       distance    &nearest,
                        Contact  &contact, const bool       occlusion) const
    {
        traversal_stack<STACK_SIZE> stack(root, world);
        const distance3 &invdir = 1 / direction;

        bool hit = false;
        nearest = range;

        while (!stack.empty())
        {
            auto s = stack.pop();
            if (s.hit < nearest)
            {
                if (s.offset & 0x80000000)
                {
                    s.offset ^= 0x80000000; /* Decode this leaf offset. */
                    hit |= lookup(origin, direction, s, nearest, contact);
                    if (occlusion && hit) return true; /* Voxel is hit. */
                }
                else
                {
                    size_t last = stack.position();
                    auto current = nodes[s.offset];
                    for (size_t t = 0; t < 8; ++t)
                    {
                        uint32_t child = current.child[t];
                        if (child == 0x00000000) continue;
                        auto node = s.subdivide(child, t);

                        if (intersect(origin, invdir, node.cube, node.hit))
                            if (node.hit < nearest) stack.push(node);
                    }

                    /* Push back to front. */
                    stack.special_sort(last);
                }
            }
        }

        return hit;
	} __attribute__ ((hot))

    // this will be done in a separate program later on (SVO's will be
    // loaded on the fly, no time to build them while streaming voxels)
    uint32_t build_SVO(int depth, const aabb &cube)
    {
        if (depth == 0)
        {
            // this is a leaf - add voxel

            uint16_t normal, material;
            get_voxel_data(cube, normal, material);

            // encode leaf data into 32-bit offset
            return encode_leaf(normal, material);
        }

        Node *node = alloc_node();

        // build children here
        for (int t = 0; t < 8; ++t)
        {
            aabb child = split_node(cube, t);

            if (!contains_voxels(child)) node->child[t] = 0;
            else node->child[t] = build_SVO(depth - 1, child);
        }

        return (uint32_t)(node - nodes);
    }

    float heightmap(distance x, distance z) const // TEMPORARY
    {
        //return 0.05f * (sin(x) + cos(z)) - 0.7f;

        if ((x <= -0.525f) || (x >= 0.6f)) return std::numeric_limits<distance>::infinity();
        if ((z <= 0.2f)) return std::numeric_limits<distance>::infinity();

        return -0.7f + 0.03f * (sin(15 * z) + sin(10 * x + 1));

        //return -2.0f/3.0f + 0.2f * x * x;
    }

    math::float3 get_normal(distance x, distance z) const // TEMPORARY
    {
        distance dx = 0.2 * cos(10 * x + 1);
        distance dz = 0.3 * cos(15 * z);

        //distance dx = 0.4f * x;
        //distance dz = 0;

        return normalize(distance3(dx, 1, dz));
    }

    bool contains_voxels(const aabb &node) const // TEMPORARY
    {
        int r = 10;

        for (int px = 0; px < r; ++px)
            for (int pz = 0; pz < r; ++pz)
            {
                distance x = node.min.x + (node.max.x - node.min.x) * (distance)px / r;
                distance z = node.min.z + (node.max.z - node.min.z) * (distance)pz / r;

                distance height = heightmap(x, z);

                if ((node.min.y <= height) && (height <= node.max.y)) return true;
            }

        return false;
    }

    void get_voxel_data(const aabb &node, uint16_t &normal, uint16_t &material) const
        // TEMPORARY
    {
        int r = 10;

        for (int px = 0; px < r; ++px)
            for (int pz = 0; pz < r; ++pz)
            {
                distance x = node.min.x + (node.max.x - node.min.x) * (distance)px / r;
                distance z = node.min.z + (node.max.z - node.min.z) * (distance)pz / r;

                distance height = heightmap(x, z);

                if ((node.min.y <= height) && (height <= node.max.y))
                {
                    normal = encode_normal(get_normal(x, z));
                    material = 0;

                    return;
                }
            }
    }

    // pray your libc overcommits :)
    #define NODE_MEMORY (1024 * 1024 * 1024)

    Node *nodes;
    size_t node_offset;

    void init_mem()
    {
        nodes = (Node*)malloc(NODE_MEMORY);
        node_offset = 0;
    }

    Node *alloc_node()
    {
        Node *ptr = nodes + node_offset;
        node_offset++;
        return ptr;
    }

    uint32_t root;
};
<commit_msg>Added 3D array -> SVO construction code (ugly and slow).<commit_after>#pragma once

/* Voxel test with procedural data. */

#include "material.hpp"

#include "math/vector3.hpp"
#include <cmath>

#include <cstdint>

#include <cstddef>

#include <algorithm>

#include "contact.hpp"

#include "geometry/voxel_types.hpp"

#include "geometry/fast_stack.hpp"

#include "geometry/aabb.hpp"

// the encoding currently used for voxels imposes a maximum of 2 billion nodes
// but it may make sense to use uint64_t and use the extra 32 bits in the leaf
// nodes for fast-changing material properties (or other)
// (we'd need to know how many voxels constitute a typical world with LOD, and
//  see if double the memory usage is worth a richer & faster material system)

static const math::basic_vector3<int> offset_int[8] =
    {
        math::basic_vector3<int>(0, 0, 0),
        math::basic_vector3<int>(0, 0, 1),
        math::basic_vector3<int>(0, 1, 0),
        math::basic_vector3<int>(0, 1, 1),
        math::basic_vector3<int>(1, 0, 0),
        math::basic_vector3<int>(1, 0, 1),
        math::basic_vector3<int>(1, 1, 0),
        math::basic_vector3<int>(1, 1, 1),
    };

struct Voxel // for building only
{
    uint16_t material;
    uint16_t normal;
};

struct Node
{
    uint32_t child[8];
};

uint32_t encode_leaf(const uint16_t &normal, const uint16_t &material)
{
    return (((material & 0x7FFF) << 16) | normal) | 0x80000000;
}

// assumes the high bit marker has already been removed
void decode_leaf(const uint32_t &leaf, uint16_t &normal, uint16_t &material)
{
    material = leaf >> 16;
    normal = leaf & 0xFFFF;
}

#define RESOLUTION 256

#define svo_depth 7 // TEMPORARY (will not be hardcoded later)

#define STACK_SIZE (4 * svo_depth) // can probably bring this down with some mathematical analysis of worst-case SVO traversal
                                   // (until we figure out how stackless traversal works, anyway)
                                   // (it doesn't really matter on the CPU due to how the stack works, but will be a killer on
                                   // the GPU as it will increase register pressure and kill parallelism ---> need stackless)

static distance3 light_pos = distance3(0.2f, -0.35f, 0.3f);

class VoxelTest
{
public:
    distance3 light() const
    {
        return light_pos;
    }

    bool intersects(const distance3 &origin, const distance3 &direction,
		            distance &dist, Contact &contact) const
	{
        return traverse(origin, direction,
                        std::numeric_limits<distance>::infinity(), dist, contact, false);
	}

    bool occludes(const distance3 &origin, const distance3 &direction,
                  distance &dist, distance target_dist) const
    {
        Contact contact;

        return traverse(origin, direction,
                        target_dist, dist, contact, true);
    }

    bool occludes(const distance3 &origin, const distance3 &direction,
                  distance target_dist) const
    {
        distance dist;
        Contact contact;

        return traverse(origin, direction,
                        target_dist, dist, contact, true);
    }

    bool occludes(const distance3 &origin, const distance3 &direction) const
    {
        return occludes(origin, direction, std::numeric_limits<distance>::infinity());
    }

	VoxelTest()
	{
	    printf("Building SVO (this is done only once).\n");
	    init_mem();
	    root = build_SVO(svo_depth, world, math::basic_vector3<int>(0, 0, 0), math::basic_vector3<int>(RESOLUTION - 1, RESOLUTION - 1, RESOLUTION - 1));
	    printf("SVO built (%zu nodes, depth = %d).\n",
	           node_offset, svo_depth);
	    free_mem();
	}

private:
    const aabb world = aabb{distance3(-1, -1, -1), distance3(1, 1, 1)};

    // looks up a voxel through its memory address (this could be an offset later on
    // for virtualization) and fills in an appropriate Contact structure to indicate
    // the material and surface normal, when applicable

    // this function has some pretty strong invariants to maintain, pay attention.
    // (read: if the invariants are not maintained, traversal will FAIL horribly)

    // (procedural data generation can happen here as well)
    inline
    bool lookup(const  distance3 &origin, const distance3 &direction,
                const stack_item   &leaf,       distance    &nearest,
                                                    Contact &contact) const
    {
        // default implementation, voxels are cubic and solid

        (void)origin;
        (void)direction;

        decode_leaf(leaf.offset, contact.normal, contact.material);

        nearest = leaf.hit; // IMPORTANT: you must set "nearest" to the
        // nearest intersection within the voxel's bounding box, IF AND
        // ONLY IF this intersection is closer than the currently recorded
        // "nearest" value (and if this is the case, populate "contact",
        // else LEAVE IT ALONE).

        return true; // return if and only if "nearest" was modified
    } __attribute__ ((hot))

    // this is the heart of the voxel renderer, the SVO traversal code
    // this is where optimization efforts should be focused
    // current optimizations and todo's:
    // DONE: convert to iteration and use a stack
    // TODO: implement and benchmark stackless traversal algorithms
    // DONE: uses early rejection by sorting children
    // DONE: fix remaining bugs

    // CURRENT REASONS FOR BEING SLOW:
    // 1. no SSE vector instructions  [WIP]
    // 2. unnecessary ray_aabb call in leaf [fixed]
    // 3. recursion [fixed]
    // 4. "intersections" buffer not optimized [fixed]
    // 5. tree nodes allocated via malloc(), poor locality [fixed]
    // 6. ray_aabb is not optimized at all  [fixed]
    // 7. possible algorithmic improvements?

    // QUESTIONS TO RESOLVE:
    // 1. do we need "far" in the "intersections" buffer? [NO]
    // 2. are there any bugs? need a known voxel data set to test against
    //    (do that once we have interactivity, to better locate glitches)

    // ADDITIONAL INFO:
    // - final tree will potentially be very deep, with up to 64 levels
    //   (32 levels --> 64km^3 with 0.015 mm resolution)
    // - procedural data generation can be done outside the tree, once
    //   a voxel is intersected, by generating procedural data *inside*
    //   the intersected voxel, depending on its material
    //   (this is actually a REALLY GOOD idea as it completely gets rid
    //    of any cubic artifacts and improves subpixel performance)
    // - 64 levels --> 1800 AU^3 with 0.015 mm resolution
    //   (that's 274 billion km^3, I trust this will be enough)
    // - possibly use a hybrid approach, with two trees, one handling large
    //   64km^3 "chunks", optimized for ultra fast traversal, and another
    //   which focuses on culling chunks to improve performance
    bool traverse(const distance3 &origin, const distance3 &direction,
                  const distance   &range,       distance    &nearest,
                        Contact  &contact, const bool       occlusion) const
    {
        traversal_stack<STACK_SIZE> stack(root, world);
        const distance3 &invdir = 1 / direction;

        bool hit = false;
        nearest = range;

        while (!stack.empty())
        {
            auto s = stack.pop();
            if (s.hit < nearest)
            {
                if (s.offset & 0x80000000)
                {
                    s.offset ^= 0x80000000; /* Decode this leaf offset. */
                    hit |= lookup(origin, direction, s, nearest, contact);
                    if (occlusion && hit) return true; /* Voxel is hit. */
                }
                else
                {
                    size_t last = stack.position();
                    auto current = nodes[s.offset];
                    for (size_t t = 0; t < 8; ++t)
                    {
                        uint32_t child = current.child[t];
                        if (child == 0x00000000) continue;
                        auto node = s.subdivide(child, t);

                        if (intersect(origin, invdir, node.cube, node.hit))
                            if (node.hit < nearest) stack.push(node);
                    }

                    /* Push back to front. */
                    stack.special_sort(last);
                }
            }
        }

        return hit;
	} __attribute__ ((hot))

	void split_int(const math::basic_vector3<int> &min, const math::basic_vector3<int> &max, int t,
	               math::basic_vector3<int> &child_min, math::basic_vector3<int> &child_max)
	{
	    math::basic_vector3<int> extent = (max - min) / 2;
        math::basic_vector3<int> p = min + extent * offset_int[t];
        child_min = p;
        child_max = p + extent;
	}

    // this will be done in a separate program later on (SVO's will be
    // loaded on the fly, no time to build them while streaming voxels)
    uint32_t build_SVO(int depth, const aabb &cube, const math::basic_vector3<int> &min, const math::basic_vector3<int> &max)
    {
        if (depth == 0)
        {
            // this is a leaf - add voxel

            uint16_t normal, material;
            get_voxel_data(min, max, normal, material);

            // encode leaf data into 32-bit offset
            return encode_leaf(normal, material);
        }

        Node *node = alloc_node();

        // build children here
        for (int t = 0; t < 8; ++t)
        {
            aabb child = split_node(cube, t);

            math::basic_vector3<int> child_min, child_max;
            split_int(min, max, t, child_min, child_max);

            if (!contains_voxels(child_min, child_max)) node->child[t] = 0;
            else node->child[t] = build_SVO(depth - 1, child, child_min, child_max);
        }

        return (uint32_t)(node - nodes);
    }

    float heightmap(distance x, distance z) const // TEMPORARY
    {
        //return 0.05f * (sin(x) + cos(z)) - 0.7f;

        //if ((x <= -0.525f) || (x >= 0.6f)) return std::numeric_limits<distance>::infinity();
        //if ((z <= 0.2f)) return std::numeric_limits<distance>::infinity();

        return -0.7f + 0.03f * (sin(15 * z) + sin(10 * x + 1));

        //return -2.0f/3.0f + 0.2f * x * x;
    }

    math::float3 get_normal(distance x, distance z) const // TEMPORARY
    {
        distance dx = 0.2 * cos(10 * x + 1);
        distance dz = 0.3 * cos(15 * z);

        //distance dx = 0.4f * x;
        //distance dz = 0;

        return normalize(distance3(dx, 1, dz));
    }

    bool contains_voxels(const math::basic_vector3<int> &min, const math::basic_vector3<int> &max) const // TEMPORARY
    {
        /*int r = 10;

        for (int px = 0; px < r; ++px)
            for (int pz = 0; pz < r; ++pz)
            {
                distance x = node.min.x + (node.max.x - node.min.x) * (distance)px / r;
                distance z = node.min.z + (node.max.z - node.min.z) * (distance)pz / r;

                distance height = heightmap(x, z);

                if ((node.min.y <= height) && (height <= node.max.y)) return true;
            }

        return false;*/

        for (int x = min.x; x < max.x; ++x)
            for (int y = min.y; y < max.y; ++y)
                for (int z = min.z; z < max.z; ++z)
                    if (data[x][y][z].material != 0xFFFF) return true;

        return false;
    }

    void get_voxel_data(const math::basic_vector3<int> &min, const math::basic_vector3<int> &max, uint16_t &normal, uint16_t &material) const
        // TEMPORARY
    {
        /*int r = 10;

        for (int px = 0; px < r; ++px)
            for (int pz = 0; pz < r; ++pz)
            {
                distance x = node.min.x + (node.max.x - node.min.x) * (distance)px / r;
                distance z = node.min.z + (node.max.z - node.min.z) * (distance)pz / r;

                distance height = heightmap(x, z);

                if ((node.min.y <= height) && (height <= node.max.y))
                {
                    normal = encode_normal(get_normal(x, z));
                    material = 0;

                    return;
                }
            }*/

        int x = min.x;
        int y = min.y;
        int z = min.z;

        normal = data[x][y][z].normal;
        material = data[x][y][z].material;
    }

    Voxel ***data;

    void alloc_data()
    {
        data = new Voxel**[RESOLUTION];

        for (int x = 0; x < RESOLUTION; ++x)
        {
            data[x] = new Voxel*[RESOLUTION];

            for (int y = 0; y < RESOLUTION; ++y)
            {
                data[x][y] = new Voxel[RESOLUTION];
            }
        }
    }

    void free_mem()
    {
        for (int x = 0; x < RESOLUTION; ++x)
            for (int y = 0; y < RESOLUTION; ++y)
                delete[] data[x][y];

        for (int x = 0; x < RESOLUTION; ++x)
            delete[] data[x];

        delete[] data;
    }

    void clear_data()
    {
        for (int x = 0; x < RESOLUTION; ++x)
            for (int y = 0; y < RESOLUTION; ++y)
                for (int z = 0; z < RESOLUTION; ++z)
                    data[x][y][z].material = 0xFFFF;
    }

    void filter_data()
    {
        for (int x = 1; x < RESOLUTION - 1; ++x)
            for (int y = 1; y < RESOLUTION - 1; ++y)
                for (int z = 1; z < RESOLUTION - 1; ++z)
                {
                    if ((data[x - 1][y][z].material != 0xFFFF)
                     && (data[x + 1][y][z].material != 0xFFFF)
                     && (data[x][y - 1][z].material != 0xFFFF)
                     && (data[x][y + 1][z].material != 0xFFFF)
                     && (data[x][y][z - 1].material != 0xFFFF)
                     && (data[x][y][z + 1].material != 0xFFFF))
                    {
                        data[x][y][z].material = 0xFFFF;
                    }
                }
    }

    void gen_data()
    {
        for (int x = 0; x < RESOLUTION; ++x)
            for (int y = 0; y < RESOLUTION; ++y)
                for (int z = 0; z < RESOLUTION; ++z)
                {
                    float px = ((float)x / RESOLUTION - 0.5f) * 2;
                    float py = ((float)y / RESOLUTION - 0.5f) * 2;
                    float pz = ((float)z / RESOLUTION - 0.5f) * 2;

                    if (py <= heightmap(px, pz))
                    {
                        data[x][y][z].material = 0;

                        data[x][y][z].normal = encode_normal(get_normal(px, pz));
                    }
                }
    }

    void load_model()
    {
        alloc_data();

        clear_data();

        gen_data();

        filter_data();
    }

    // pray your libc overcommits :)
    #define NODE_MEMORY (1024 * 1024 * 1024)

    Node *nodes;
    size_t node_offset;

    void init_mem()
    {
        nodes = (Node*)malloc(NODE_MEMORY);
        node_offset = 0;
        load_model();
    }

    Node *alloc_node()
    {
        Node *ptr = nodes + node_offset;
        node_offset++;
        return ptr;
    }

    uint32_t root;
};
<|endoftext|>


<commit_before>//
//     Copyright (C) Pixar. All rights reserved.
//
//     This license governs use of the accompanying software. If you
//     use the software, you accept this license. If you do not accept
//     the license, do not use the software.
//
//     1. Definitions
//     The terms "reproduce," "reproduction," "derivative works," and
//     "distribution" have the same meaning here as under U.S.
//     copyright law.  A "contribution" is the original software, or
//     any additions or changes to the software.
//     A "contributor" is any person or entity that distributes its
//     contribution under this license.
//     "Licensed patents" are a contributor's patent claims that read
//     directly on its contribution.
//
//     2. Grant of Rights
//     (A) Copyright Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free copyright license to reproduce its contribution,
//     prepare derivative works of its contribution, and distribute
//     its contribution or any derivative works that you create.
//     (B) Patent Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free license under its licensed patents to make, have
//     made, use, sell, offer for sale, import, and/or otherwise
//     dispose of its contribution in the software or derivative works
//     of the contribution in the software.
//
//     3. Conditions and Limitations
//     (A) No Trademark License- This license does not grant you
//     rights to use any contributor's name, logo, or trademarks.
//     (B) If you bring a patent claim against any contributor over
//     patents that you claim are infringed by the software, your
//     patent license from such contributor to the software ends
//     automatically.
//     (C) If you distribute any portion of the software, you must
//     retain all copyright, patent, trademark, and attribution
//     notices that are present in the software.
//     (D) If you distribute any portion of the software in source
//     code form, you may do so only under this license by including a
//     complete copy of this license with your distribution. If you
//     distribute any portion of the software in compiled or object
//     code form, you may only do so under a license that complies
//     with this license.
//     (E) The software is licensed "as-is." You bear the risk of
//     using it. The contributors give no express warranties,
//     guarantees or conditions. You may have additional consumer
//     rights under your local laws which this license cannot change.
//     To the extent permitted under your local laws, the contributors
//     exclude the implied warranties of merchantability, fitness for
//     a particular purpose and non-infringement.
//

#include "../osd/gcdKernel.h"
#include "../osd/cpuKernel.h"
#include "../osd/vertexDescriptor.h"

#include <math.h>

namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

const int GCD_WORK_STRIDE = 32;

void OsdGcdComputeFace(
    const OsdVertexDescriptor *vdesc, float * vertex, float * varying,
    const int *F_IT, const int *F_ITa, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int h = F_ITa[2*i];
        int n = F_ITa[2*i+1];

        float weight = 1.0f/n;

        // XXX: should use local vertex struct variable instead of
        // accumulating directly into global memory.
        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        for (int j = 0; j < n; ++j) {
            int index = F_IT[h+j];
            vdesc->AddWithWeight(vertex, dstIndex, index, weight);
            vdesc->AddVaryingWithWeight(varying, dstIndex, index, weight);
        }
    });
}

void OsdGcdComputeEdge(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *E_IT, const float *E_W, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeEdge(vdesc, vertex, varying, E_IT, E_W, offset,
            start_i, end_i);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeEdge(vdesc, vertex, varying, E_IT, E_W, offset,
            start_e, end_e);
}

void OsdGcdComputeVertexA(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, const float *V_W,
    int offset, int start, int end, int pass,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeVertexA(vdesc, vertex, varying, V_ITa, V_W, offset,
            start_i, end_i, pass);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeVertexA(vdesc, vertex, varying, V_ITa, V_W, offset,
            start_e, end_e, pass);
}

void OsdGcdComputeVertexB(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, const int *V_IT, const float *V_W,
    int offset, int start, int end,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeVertexB(vdesc, vertex, varying, V_ITa, V_IT, V_W, offset,
            start_i, end_i);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeVertexB(vdesc, vertex, varying, V_ITa, V_IT, V_W, offset,
            start_e, end_e);
}

void OsdGcdComputeLoopVertexB(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, const int *V_IT, const float *V_W,
    int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int h = V_ITa[5*i];
        int n = V_ITa[5*i+1];
        int p = V_ITa[5*i+2];

        float weight = V_W[i];
        float wp = 1.0f/static_cast<float>(n);
        float beta = 0.25f * cosf(static_cast<float>(M_PI) * 2.0f * wp) + 0.375f;
        beta = beta * beta;
        beta = (0.625f - beta) * wp;

        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        vdesc->AddWithWeight(vertex, dstIndex, p, weight * (1.0f - (beta * n)));

        for (int j = 0; j < n; ++j)
            vdesc->AddWithWeight(vertex, dstIndex, V_IT[h+j], weight * beta);

        vdesc->AddVaryingWithWeight(varying, dstIndex, p, 1.0f);
    });
}

void OsdGcdComputeBilinearEdge(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *E_IT, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int eidx0 = E_IT[2*i+0];
        int eidx1 = E_IT[2*i+1];

        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        vdesc->AddWithWeight(vertex, dstIndex, eidx0, 0.5f);
        vdesc->AddWithWeight(vertex, dstIndex, eidx1, 0.5f);

        vdesc->AddVaryingWithWeight(varying, dstIndex, eidx0, 0.5f);
        vdesc->AddVaryingWithWeight(varying, dstIndex, eidx1, 0.5f);
    });
}

void OsdGcdComputeBilinearVertex(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int p = V_ITa[i];

        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        vdesc->AddWithWeight(vertex, dstIndex, p, 1.0f);
        vdesc->AddVaryingWithWeight(varying, dstIndex, p, 1.0f);
    });
}

void OsdGcdEditVertexAdd(
    const OsdVertexDescriptor *vdesc, float *vertex,
    int primVarOffset, int primVarWidth, int vertexCount,
    const int *editIndices, const float *editValues,
    dispatch_queue_t gcdq) {

    dispatch_apply(vertexCount, gcdq, ^(size_t blockIdx){
        int i = blockIdx;
        vdesc->ApplyVertexEditAdd(vertex, primVarOffset, primVarWidth,
                                  editIndices[i], &editValues[i*primVarWidth]);
    });
}

void OsdGcdEditVertexSet(
    const OsdVertexDescriptor *vdesc, float *vertex,
    int primVarOffset, int primVarWidth, int vertexCount,
    const int *editIndices, const float *editValues,
    dispatch_queue_t gcdq) {

    dispatch_apply(vertexCount, gcdq, ^(size_t blockIdx){
        int i = blockIdx;
        vdesc->ApplyVertexEditSet(vertex, primVarOffset, primVarWidth,
                                  editIndices[i], &editValues[i*primVarWidth]);
    });
}

}  // end namespace OPENSUBDIV_VERSION
}  // end namespace OpenSubdiv
<commit_msg>gcd: convert face loop to work in 32 item size batches. MBP6,2 (2 core 4 thread), catmark_car Lv4: 31.2ms CPU, 15.8ms GCD (was 22ms)<commit_after>//
//     Copyright (C) Pixar. All rights reserved.
//
//     This license governs use of the accompanying software. If you
//     use the software, you accept this license. If you do not accept
//     the license, do not use the software.
//
//     1. Definitions
//     The terms "reproduce," "reproduction," "derivative works," and
//     "distribution" have the same meaning here as under U.S.
//     copyright law.  A "contribution" is the original software, or
//     any additions or changes to the software.
//     A "contributor" is any person or entity that distributes its
//     contribution under this license.
//     "Licensed patents" are a contributor's patent claims that read
//     directly on its contribution.
//
//     2. Grant of Rights
//     (A) Copyright Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free copyright license to reproduce its contribution,
//     prepare derivative works of its contribution, and distribute
//     its contribution or any derivative works that you create.
//     (B) Patent Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free license under its licensed patents to make, have
//     made, use, sell, offer for sale, import, and/or otherwise
//     dispose of its contribution in the software or derivative works
//     of the contribution in the software.
//
//     3. Conditions and Limitations
//     (A) No Trademark License- This license does not grant you
//     rights to use any contributor's name, logo, or trademarks.
//     (B) If you bring a patent claim against any contributor over
//     patents that you claim are infringed by the software, your
//     patent license from such contributor to the software ends
//     automatically.
//     (C) If you distribute any portion of the software, you must
//     retain all copyright, patent, trademark, and attribution
//     notices that are present in the software.
//     (D) If you distribute any portion of the software in source
//     code form, you may do so only under this license by including a
//     complete copy of this license with your distribution. If you
//     distribute any portion of the software in compiled or object
//     code form, you may only do so under a license that complies
//     with this license.
//     (E) The software is licensed "as-is." You bear the risk of
//     using it. The contributors give no express warranties,
//     guarantees or conditions. You may have additional consumer
//     rights under your local laws which this license cannot change.
//     To the extent permitted under your local laws, the contributors
//     exclude the implied warranties of merchantability, fitness for
//     a particular purpose and non-infringement.
//

#include "../osd/gcdKernel.h"
#include "../osd/cpuKernel.h"
#include "../osd/vertexDescriptor.h"

#include <math.h>

namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

const int GCD_WORK_STRIDE = 32;

void OsdGcdComputeFace(
    const OsdVertexDescriptor *vdesc, float * vertex, float * varying,
    const int *F_IT, const int *F_ITa, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeFace(vdesc, vertex, varying, F_IT, F_ITa, offset,
            start_i, end_i);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeFace(vdesc, vertex, varying, F_IT, F_ITa, offset,
            start_e, end_e);
}

void OsdGcdComputeEdge(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *E_IT, const float *E_W, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeEdge(vdesc, vertex, varying, E_IT, E_W, offset,
            start_i, end_i);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeEdge(vdesc, vertex, varying, E_IT, E_W, offset,
            start_e, end_e);
}

void OsdGcdComputeVertexA(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, const float *V_W,
    int offset, int start, int end, int pass,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeVertexA(vdesc, vertex, varying, V_ITa, V_W, offset,
            start_i, end_i, pass);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeVertexA(vdesc, vertex, varying, V_ITa, V_W, offset,
            start_e, end_e, pass);
}

void OsdGcdComputeVertexB(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, const int *V_IT, const float *V_W,
    int offset, int start, int end,
    dispatch_queue_t gcdq) {

    const int workSize = end-start;
    dispatch_apply(workSize/GCD_WORK_STRIDE, gcdq, ^(size_t blockIdx){
        const int start_i = start + blockIdx*GCD_WORK_STRIDE;
        const int end_i = start_i + GCD_WORK_STRIDE;
        OsdCpuComputeVertexB(vdesc, vertex, varying, V_ITa, V_IT, V_W, offset,
            start_i, end_i);
    });
    const int start_e = end - workSize%GCD_WORK_STRIDE;
    const int end_e = end;
    if (start_e < end_e)
        OsdCpuComputeVertexB(vdesc, vertex, varying, V_ITa, V_IT, V_W, offset,
            start_e, end_e);
}

void OsdGcdComputeLoopVertexB(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, const int *V_IT, const float *V_W,
    int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int h = V_ITa[5*i];
        int n = V_ITa[5*i+1];
        int p = V_ITa[5*i+2];

        float weight = V_W[i];
        float wp = 1.0f/static_cast<float>(n);
        float beta = 0.25f * cosf(static_cast<float>(M_PI) * 2.0f * wp) + 0.375f;
        beta = beta * beta;
        beta = (0.625f - beta) * wp;

        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        vdesc->AddWithWeight(vertex, dstIndex, p, weight * (1.0f - (beta * n)));

        for (int j = 0; j < n; ++j)
            vdesc->AddWithWeight(vertex, dstIndex, V_IT[h+j], weight * beta);

        vdesc->AddVaryingWithWeight(varying, dstIndex, p, 1.0f);
    });
}

void OsdGcdComputeBilinearEdge(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *E_IT, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int eidx0 = E_IT[2*i+0];
        int eidx1 = E_IT[2*i+1];

        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        vdesc->AddWithWeight(vertex, dstIndex, eidx0, 0.5f);
        vdesc->AddWithWeight(vertex, dstIndex, eidx1, 0.5f);

        vdesc->AddVaryingWithWeight(varying, dstIndex, eidx0, 0.5f);
        vdesc->AddVaryingWithWeight(varying, dstIndex, eidx1, 0.5f);
    });
}

void OsdGcdComputeBilinearVertex(
    const OsdVertexDescriptor *vdesc, float *vertex, float *varying,
    const int *V_ITa, int offset, int start, int end,
    dispatch_queue_t gcdq) {

    dispatch_apply(end-start, gcdq, ^(size_t blockIdx){
        int i = start+blockIdx;
        int p = V_ITa[i];

        int dstIndex = offset + i;
        vdesc->Clear(vertex, varying, dstIndex);

        vdesc->AddWithWeight(vertex, dstIndex, p, 1.0f);
        vdesc->AddVaryingWithWeight(varying, dstIndex, p, 1.0f);
    });
}

void OsdGcdEditVertexAdd(
    const OsdVertexDescriptor *vdesc, float *vertex,
    int primVarOffset, int primVarWidth, int vertexCount,
    const int *editIndices, const float *editValues,
    dispatch_queue_t gcdq) {

    dispatch_apply(vertexCount, gcdq, ^(size_t blockIdx){
        int i = blockIdx;
        vdesc->ApplyVertexEditAdd(vertex, primVarOffset, primVarWidth,
                                  editIndices[i], &editValues[i*primVarWidth]);
    });
}

void OsdGcdEditVertexSet(
    const OsdVertexDescriptor *vdesc, float *vertex,
    int primVarOffset, int primVarWidth, int vertexCount,
    const int *editIndices, const float *editValues,
    dispatch_queue_t gcdq) {

    dispatch_apply(vertexCount, gcdq, ^(size_t blockIdx){
        int i = blockIdx;
        vdesc->ApplyVertexEditSet(vertex, primVarOffset, primVarWidth,
                                  editIndices[i], &editValues[i*primVarWidth]);
    });
}

}  // end namespace OPENSUBDIV_VERSION
}  // end namespace OpenSubdiv
<|endoftext|>


<commit_before>#include <DS18B20.h>

DS18B20::DS18B20(uint8_t pin) : oneWire(OneWire(pin)) {
    resetSearch();
    sendCommand(SKIP_ROM, READ_POWER_SUPPLY);
    globalPowerMode = oneWire.read_bit();

    while (selectNext()) {
        uint8_t resolution = getResolution();

        if (resolution > globalResolution) {
            globalResolution = resolution;
        }

        numberOfDevices++;
    }
}

uint8_t DS18B20::select(uint8_t address[]) {
    if (isConnected(address)) {
        memcpy(selectedAddress, address, 8);

        if (readScratchpad()) {
            selectedResolution = getResolution();

            sendCommand(MATCH_ROM, READ_POWER_SUPPLY);
            selectedPowerMode = oneWire.read_bit();

            return 1;
        }
    }

    return 0;
}

uint8_t DS18B20::selectNext() {
    if (oneWireSearch(SEARCH_ROM)) {
        return select(searchAddress);
    }

    return 0;
}

uint8_t DS18B20::selectNextAlarm() {
    if (oneWireSearch(ALARM_SEARCH)) {
        return select(searchAddress);
    }

    return 0;
}

void DS18B20::resetSearch() {
    lastDiscrepancy = 0;
    lastDevice = 0;
}

float DS18B20::getTempC() {
    sendCommand(MATCH_ROM, CONVERT_T, !selectedPowerMode);
    delayForConversion(selectedResolution, selectedPowerMode);
    readScratchpad();
    uint8_t lsb = selectedScratchpad[TEMP_LSB];
    uint8_t msb = selectedScratchpad[TEMP_MSB];

    switch (selectedResolution) {
        case 9:
            lsb &= 0xF8;
            break;
        case 10:
            lsb &= 0xFC;
            break;
        case 11:
            lsb &= 0xFE;
            break;
    }

    uint8_t sign = msb & 0x80;
    int16_t temp = (msb << 8) + lsb;

    if (sign) {
        temp = ((temp ^ 0xffff) + 1) * -1;
    }

    return temp / 16.0;
}

float DS18B20::getTempF() {
    return getTempC() * 1.8 + 32;
}

uint8_t DS18B20::getResolution() {
    switch (selectedScratchpad[CONFIGURATION]) {
        case RES_9_BIT:
            return 9;
        case RES_10_BIT:
            return 10;
        case RES_11_BIT:
            return 11;
        case RES_12_BIT:
            return 12;
    }
}

void DS18B20::setResolution(uint8_t resolution) {
    resolution = constrain(resolution, 9, 12);

    switch (resolution) {
        case 9:
            selectedScratchpad[CONFIGURATION] = RES_9_BIT;
            break;
        case 10:
            selectedScratchpad[CONFIGURATION] = RES_10_BIT;
            break;
        case 11:
            selectedScratchpad[CONFIGURATION] = RES_11_BIT;
            break;
        case 12:
            selectedScratchpad[CONFIGURATION] = RES_12_BIT;
            break;
    }

    if (resolution > globalResolution) {
        globalResolution = resolution;
    }

    writeScratchpad();
}

uint8_t DS18B20::getPowerMode() {
    return selectedPowerMode;
}

uint8_t DS18B20::getFamilyCode() {
    return selectedAddress[0];
}

void DS18B20::getAddress(uint8_t address[]) {
    memcpy(address, selectedAddress, 8);
}

void DS18B20::doConversion() {
    sendCommand(SKIP_ROM, CONVERT_T, !globalPowerMode);
    delayForConversion(globalResolution, globalPowerMode);
}

uint8_t DS18B20::getNumberOfDevices() {
    return numberOfDevices;
}

uint8_t DS18B20::hasAlarm() {
    uint8_t oldResolution = selectedResolution;
    setResolution(9);
    float temp = getTempC();
    setResolution(oldResolution);
    return ((temp <= selectedScratchpad[ALARM_LOW]) || (temp >= selectedScratchpad[ALARM_HIGH]));
}

void DS18B20::setAlarms(int8_t alarmLow, int8_t alarmHigh) {
    setAlarmLow(alarmLow);
    setAlarmHigh(alarmHigh);
    writeScratchpad();
}

int8_t DS18B20::getAlarmLow() {
    return selectedScratchpad[ALARM_LOW];
}

void DS18B20::setAlarmLow(int8_t alarmLow) {
    alarmLow = constrain(alarmLow, -55, 125);
    selectedScratchpad[ALARM_LOW] = alarmLow;
    writeScratchpad();
}

int8_t DS18B20::getAlarmHigh() {
    return selectedScratchpad[ALARM_HIGH];
}

void DS18B20::setAlarmHigh(int8_t alarmHigh) {
    alarmHigh = constrain(alarmHigh, -55, 125);
    selectedScratchpad[ALARM_HIGH] = alarmHigh;
    writeScratchpad();
}

void DS18B20::setRegisters(int8_t lowRegister, int8_t highRegister) {
    setAlarms(lowRegister, highRegister);
}

int8_t DS18B20::getLowRegister() {
    return getAlarmLow();
}

void DS18B20::setLowRegister(int8_t lowRegister) {
    setAlarmLow(lowRegister);
}

int8_t DS18B20::getHighRegister() {
    return getAlarmHigh();
}

void DS18B20::setHighRegister(int8_t highRegister) {
    setAlarmHigh(highRegister);
}

uint8_t DS18B20::readScratchpad() {
    sendCommand(MATCH_ROM, READ_SCRATCHPAD);

    for (uint8_t i = 0; i < SIZE_SCRATCHPAD; i++) {
        selectedScratchpad[i] = oneWire.read();
    }

    return OneWire::crc8(selectedScratchpad, 8) == selectedScratchpad[CRC8];
}

void DS18B20::writeScratchpad() {
    sendCommand(MATCH_ROM, WRITE_SCRATCHPAD);
    oneWire.write(selectedScratchpad[ALARM_HIGH]);
    oneWire.write(selectedScratchpad[ALARM_LOW]);
    oneWire.write(selectedScratchpad[CONFIGURATION]);
    sendCommand(MATCH_ROM, COPY_SCRATCHPAD, !selectedPowerMode);

    if (!selectedPowerMode) {
        delay(10);
    }
}

uint8_t DS18B20::sendCommand(uint8_t romCommand) {
    if (!oneWire.reset()) {
        return 0;
    }

    switch (romCommand) {
        case SEARCH_ROM:
        case SKIP_ROM:
        case ALARM_SEARCH:
            oneWire.write(romCommand);
            break;
        case MATCH_ROM:
            oneWire.select(selectedAddress);
            break;
        default:
            return 0;
    }

    return 1;
}

uint8_t DS18B20::sendCommand(uint8_t romCommand, uint8_t functionCommand, uint8_t power) {
    if (!sendCommand(romCommand)) {
        return 0;
    }

    switch (functionCommand) {
        case CONVERT_T:
        case COPY_SCRATCHPAD:
            oneWire.write(functionCommand, power);
            break;
        case WRITE_SCRATCHPAD:
        case READ_SCRATCHPAD:
        case READ_POWER_SUPPLY:
            oneWire.write(functionCommand);
            break;
        default:
            return 0;
    }

    return 1;
}

uint8_t DS18B20::oneWireSearch(uint8_t romCommand) {
    if (lastDevice || !sendCommand(romCommand)) {
        resetSearch();
        return 0;
    }

    uint8_t lastZero = 0;
    uint8_t direction, byteNumber, bitNumber, currentBit, currentBitComp;

    for (uint8_t bitPosition = 0; bitPosition < 64; bitPosition++) {
        currentBit = oneWire.read_bit();
        currentBitComp = oneWire.read_bit();

        if (currentBit && currentBitComp) {
            lastDiscrepancy = 0;
            return 0;
        }

        byteNumber = bitPosition / 8;
        bitNumber = bitPosition % 8;

        if (!currentBit && !currentBitComp) {
            if (bitPosition == lastDiscrepancy) {
                direction = 1;
            } else if (bitPosition > lastDiscrepancy) {
                direction = 0;
                lastZero = bitPosition;
            } else {
                direction = bitRead(searchAddress[byteNumber], bitNumber);

                if (!direction) {
                    lastZero = bitPosition;
                }
            }
        } else {
            direction = currentBit;
        }

        bitWrite(searchAddress[byteNumber], bitNumber, direction);
        oneWire.write_bit(direction);
    }

    lastDiscrepancy = lastZero;

    if (!lastDiscrepancy) {
        lastDevice = 1;
    }

    return 1;
}

uint8_t DS18B20::isConnected(uint8_t address[]) {
    if (!sendCommand(SEARCH_ROM)) {
        return 0;
    }

    uint8_t currentBit, currentBitComp, byteNumber, bitNumber;

    for (uint8_t bitPosition = 0; bitPosition < 64; bitPosition++) {
        currentBit = oneWire.read_bit();
        currentBitComp = oneWire.read_bit();

        if (currentBit && currentBitComp) {
            return 0;
        }

        byteNumber = bitPosition / 8;
        bitNumber = bitPosition % 8;
        oneWire.write_bit(bitRead(address[byteNumber], bitNumber));
    }

    return 1;
}

void DS18B20::delayForConversion(uint8_t resolution, uint8_t powerMode) {
    if (powerMode) {
        while (!oneWire.read_bit());
    } else {
        switch (resolution) {
            case 9:
                delay(CONV_TIME_9_BIT);
                break;
            case 10:
                delay(CONV_TIME_10_BIT);
                break;
            case 11:
                delay(CONV_TIME_11_BIT);
                break;
            case 12:
                delay(CONV_TIME_12_BIT);
                break;
        }
    }
}
<commit_msg>Initialize class members in the constructor<commit_after>#include <DS18B20.h>

DS18B20::DS18B20(uint8_t pin) :
    oneWire(OneWire(pin)),
    numberOfDevices(0),
    globalResolution(0),
    selectedResolution(0),
    selectedPowerMode(0)
{
    resetSearch();
    sendCommand(SKIP_ROM, READ_POWER_SUPPLY);
    globalPowerMode = oneWire.read_bit();

    while (selectNext()) {
        uint8_t resolution = getResolution();

        if (resolution > globalResolution) {
            globalResolution = resolution;
        }

        numberOfDevices++;
    }
}

uint8_t DS18B20::select(uint8_t address[]) {
    if (isConnected(address)) {
        memcpy(selectedAddress, address, 8);

        if (readScratchpad()) {
            selectedResolution = getResolution();

            sendCommand(MATCH_ROM, READ_POWER_SUPPLY);
            selectedPowerMode = oneWire.read_bit();

            return 1;
        }
    }

    return 0;
}

uint8_t DS18B20::selectNext() {
    if (oneWireSearch(SEARCH_ROM)) {
        return select(searchAddress);
    }

    return 0;
}

uint8_t DS18B20::selectNextAlarm() {
    if (oneWireSearch(ALARM_SEARCH)) {
        return select(searchAddress);
    }

    return 0;
}

void DS18B20::resetSearch() {
    lastDiscrepancy = 0;
    lastDevice = 0;
}

float DS18B20::getTempC() {
    sendCommand(MATCH_ROM, CONVERT_T, !selectedPowerMode);
    delayForConversion(selectedResolution, selectedPowerMode);
    readScratchpad();
    uint8_t lsb = selectedScratchpad[TEMP_LSB];
    uint8_t msb = selectedScratchpad[TEMP_MSB];

    switch (selectedResolution) {
        case 9:
            lsb &= 0xF8;
            break;
        case 10:
            lsb &= 0xFC;
            break;
        case 11:
            lsb &= 0xFE;
            break;
    }

    uint8_t sign = msb & 0x80;
    int16_t temp = (msb << 8) + lsb;

    if (sign) {
        temp = ((temp ^ 0xffff) + 1) * -1;
    }

    return temp / 16.0;
}

float DS18B20::getTempF() {
    return getTempC() * 1.8 + 32;
}

uint8_t DS18B20::getResolution() {
    switch (selectedScratchpad[CONFIGURATION]) {
        case RES_9_BIT:
            return 9;
        case RES_10_BIT:
            return 10;
        case RES_11_BIT:
            return 11;
        case RES_12_BIT:
            return 12;
    }
}

void DS18B20::setResolution(uint8_t resolution) {
    resolution = constrain(resolution, 9, 12);

    switch (resolution) {
        case 9:
            selectedScratchpad[CONFIGURATION] = RES_9_BIT;
            break;
        case 10:
            selectedScratchpad[CONFIGURATION] = RES_10_BIT;
            break;
        case 11:
            selectedScratchpad[CONFIGURATION] = RES_11_BIT;
            break;
        case 12:
            selectedScratchpad[CONFIGURATION] = RES_12_BIT;
            break;
    }

    if (resolution > globalResolution) {
        globalResolution = resolution;
    }

    writeScratchpad();
}

uint8_t DS18B20::getPowerMode() {
    return selectedPowerMode;
}

uint8_t DS18B20::getFamilyCode() {
    return selectedAddress[0];
}

void DS18B20::getAddress(uint8_t address[]) {
    memcpy(address, selectedAddress, 8);
}

void DS18B20::doConversion() {
    sendCommand(SKIP_ROM, CONVERT_T, !globalPowerMode);
    delayForConversion(globalResolution, globalPowerMode);
}

uint8_t DS18B20::getNumberOfDevices() {
    return numberOfDevices;
}

uint8_t DS18B20::hasAlarm() {
    uint8_t oldResolution = selectedResolution;
    setResolution(9);
    float temp = getTempC();
    setResolution(oldResolution);
    return ((temp <= selectedScratchpad[ALARM_LOW]) || (temp >= selectedScratchpad[ALARM_HIGH]));
}

void DS18B20::setAlarms(int8_t alarmLow, int8_t alarmHigh) {
    setAlarmLow(alarmLow);
    setAlarmHigh(alarmHigh);
    writeScratchpad();
}

int8_t DS18B20::getAlarmLow() {
    return selectedScratchpad[ALARM_LOW];
}

void DS18B20::setAlarmLow(int8_t alarmLow) {
    alarmLow = constrain(alarmLow, -55, 125);
    selectedScratchpad[ALARM_LOW] = alarmLow;
    writeScratchpad();
}

int8_t DS18B20::getAlarmHigh() {
    return selectedScratchpad[ALARM_HIGH];
}

void DS18B20::setAlarmHigh(int8_t alarmHigh) {
    alarmHigh = constrain(alarmHigh, -55, 125);
    selectedScratchpad[ALARM_HIGH] = alarmHigh;
    writeScratchpad();
}

void DS18B20::setRegisters(int8_t lowRegister, int8_t highRegister) {
    setAlarms(lowRegister, highRegister);
}

int8_t DS18B20::getLowRegister() {
    return getAlarmLow();
}

void DS18B20::setLowRegister(int8_t lowRegister) {
    setAlarmLow(lowRegister);
}

int8_t DS18B20::getHighRegister() {
    return getAlarmHigh();
}

void DS18B20::setHighRegister(int8_t highRegister) {
    setAlarmHigh(highRegister);
}

uint8_t DS18B20::readScratchpad() {
    sendCommand(MATCH_ROM, READ_SCRATCHPAD);

    for (uint8_t i = 0; i < SIZE_SCRATCHPAD; i++) {
        selectedScratchpad[i] = oneWire.read();
    }

    return OneWire::crc8(selectedScratchpad, 8) == selectedScratchpad[CRC8];
}

void DS18B20::writeScratchpad() {
    sendCommand(MATCH_ROM, WRITE_SCRATCHPAD);
    oneWire.write(selectedScratchpad[ALARM_HIGH]);
    oneWire.write(selectedScratchpad[ALARM_LOW]);
    oneWire.write(selectedScratchpad[CONFIGURATION]);
    sendCommand(MATCH_ROM, COPY_SCRATCHPAD, !selectedPowerMode);

    if (!selectedPowerMode) {
        delay(10);
    }
}

uint8_t DS18B20::sendCommand(uint8_t romCommand) {
    if (!oneWire.reset()) {
        return 0;
    }

    switch (romCommand) {
        case SEARCH_ROM:
        case SKIP_ROM:
        case ALARM_SEARCH:
            oneWire.write(romCommand);
            break;
        case MATCH_ROM:
            oneWire.select(selectedAddress);
            break;
        default:
            return 0;
    }

    return 1;
}

uint8_t DS18B20::sendCommand(uint8_t romCommand, uint8_t functionCommand, uint8_t power) {
    if (!sendCommand(romCommand)) {
        return 0;
    }

    switch (functionCommand) {
        case CONVERT_T:
        case COPY_SCRATCHPAD:
            oneWire.write(functionCommand, power);
            break;
        case WRITE_SCRATCHPAD:
        case READ_SCRATCHPAD:
        case READ_POWER_SUPPLY:
            oneWire.write(functionCommand);
            break;
        default:
            return 0;
    }

    return 1;
}

uint8_t DS18B20::oneWireSearch(uint8_t romCommand) {
    if (lastDevice || !sendCommand(romCommand)) {
        resetSearch();
        return 0;
    }

    uint8_t lastZero = 0;
    uint8_t direction, byteNumber, bitNumber, currentBit, currentBitComp;

    for (uint8_t bitPosition = 0; bitPosition < 64; bitPosition++) {
        currentBit = oneWire.read_bit();
        currentBitComp = oneWire.read_bit();

        if (currentBit && currentBitComp) {
            lastDiscrepancy = 0;
            return 0;
        }

        byteNumber = bitPosition / 8;
        bitNumber = bitPosition % 8;

        if (!currentBit && !currentBitComp) {
            if (bitPosition == lastDiscrepancy) {
                direction = 1;
            } else if (bitPosition > lastDiscrepancy) {
                direction = 0;
                lastZero = bitPosition;
            } else {
                direction = bitRead(searchAddress[byteNumber], bitNumber);

                if (!direction) {
                    lastZero = bitPosition;
                }
            }
        } else {
            direction = currentBit;
        }

        bitWrite(searchAddress[byteNumber], bitNumber, direction);
        oneWire.write_bit(direction);
    }

    lastDiscrepancy = lastZero;

    if (!lastDiscrepancy) {
        lastDevice = 1;
    }

    return 1;
}

uint8_t DS18B20::isConnected(uint8_t address[]) {
    if (!sendCommand(SEARCH_ROM)) {
        return 0;
    }

    uint8_t currentBit, currentBitComp, byteNumber, bitNumber;

    for (uint8_t bitPosition = 0; bitPosition < 64; bitPosition++) {
        currentBit = oneWire.read_bit();
        currentBitComp = oneWire.read_bit();

        if (currentBit && currentBitComp) {
            return 0;
        }

        byteNumber = bitPosition / 8;
        bitNumber = bitPosition % 8;
        oneWire.write_bit(bitRead(address[byteNumber], bitNumber));
    }

    return 1;
}

void DS18B20::delayForConversion(uint8_t resolution, uint8_t powerMode) {
    if (powerMode) {
        while (!oneWire.read_bit());
    } else {
        switch (resolution) {
            case 9:
                delay(CONV_TIME_9_BIT);
                break;
            case 10:
                delay(CONV_TIME_10_BIT);
                break;
            case 11:
                delay(CONV_TIME_11_BIT);
                break;
            case 12:
                delay(CONV_TIME_12_BIT);
                break;
        }
    }
}
<|endoftext|>