<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <unsupported/Eigen/MatrixFunctions>

// Returns a matrix with eigenvalues clustered around 0, 1 and 2.
template<typename MatrixType>
MatrixType randomMatrixWithRealEivals(const int size)
{
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType diag = MatrixType::Zero(size, size);
  for (int i = 0; i < size; ++i) {
    diag(i, i) = Scalar(RealScalar(ei_random<int>(0,2)))
      + ei_random<Scalar>() * Scalar(RealScalar(0.01));
  }
  MatrixType A = MatrixType::Random(size, size);
  return A.inverse() * diag * A;
}

template<typename MatrixType>
void testMatrixExponential(const MatrixType& A)
{
  typedef typename ei_traits<MatrixType>::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef std::complex<RealScalar> ComplexScalar;

  for (int i = 0; i < g_repeat; i++) {
    MatrixType expA1, expA2;
    ei_matrix_exponential(A, &expA1);
    ei_matrix_function(A, StdStemFunctions<ComplexScalar>::exp, &expA2);
    VERIFY_IS_APPROX(expA1, expA2);
  }
}

template<typename MatrixType>
void testHyperbolicFunctions(const MatrixType& A)
{
  for (int i = 0; i < g_repeat; i++) {
    MatrixType sinhA, coshA, expA;
    ei_matrix_sinh(A, &sinhA);
    ei_matrix_cosh(A, &coshA);
    ei_matrix_exponential(A, &expA);
    VERIFY_IS_APPROX(sinhA, (expA - expA.inverse())/2);
    VERIFY_IS_APPROX(coshA, (expA + expA.inverse())/2);
  }
}

template<typename MatrixType>
void testGonioFunctions(const MatrixType& A)
{
  typedef ei_traits<MatrixType> Traits;
  typedef typename Traits::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef std::complex<RealScalar> ComplexScalar;
  typedef Matrix<ComplexScalar, Traits::RowsAtCompileTime,
                 Traits::ColsAtCompileTime, MatrixType::Options> ComplexMatrix;

  ComplexScalar imagUnit(0,1);
  ComplexScalar two(2,0);

  for (int i = 0; i < g_repeat; i++) {
    ComplexMatrix Ac = A.template cast<ComplexScalar>();

    ComplexMatrix exp_iA;
    ei_matrix_exponential(imagUnit * Ac, &exp_iA);

    MatrixType sinA;
    ei_matrix_sin(A, &sinA);
    ComplexMatrix sinAc = sinA.template cast<ComplexScalar>();
    VERIFY_IS_APPROX(sinAc, (exp_iA - exp_iA.inverse()) / (two*imagUnit));

    MatrixType cosA;
    ei_matrix_cos(A, &cosA);
    ComplexMatrix cosAc = cosA.template cast<ComplexScalar>();
    VERIFY_IS_APPROX(cosAc, (exp_iA + exp_iA.inverse()) / 2);
  }
}

template<typename MatrixType>
void testMatrix(const MatrixType& A)
{
  testMatrixExponential(A);
  testHyperbolicFunctions(A);
  testGonioFunctions(A);
}

template<typename MatrixType>
void testMatrixType(const MatrixType& m)
{
  // Matrices with clustered eigenvalue lead to different code paths
  // in MatrixFunction.h and are thus useful for testing.

  const int size = m.rows();
  for (int i = 0; i < g_repeat; i++) {
    testMatrix(MatrixType::Random(size, size).eval());
    testMatrix(randomMatrixWithRealEivals<MatrixType>(size));
  }
}

void test_matrix_function()
{
  CALL_SUBTEST_1(testMatrixType(Matrix<float,1,1>()));
  CALL_SUBTEST_2(testMatrixType(Matrix3cf()));
  CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8)));
  CALL_SUBTEST_4(testMatrixType(Matrix2d()));
  CALL_SUBTEST_5(testMatrixType(Matrix<double,5,5,RowMajor>()));
  CALL_SUBTEST_6(testMatrixType(Matrix4cd()));
  CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13)));
}
<commit_msg>Test matrix functions with matrices with clustered imaginary eivals. The idea is that these test MatrixFunction::swapEntriesInSchur(), which is not covered by existing tests. This did not work out as expected, but nevertheless it is a good test so I left it in.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <unsupported/Eigen/MatrixFunctions>

// Returns a matrix with eigenvalues clustered around 0, 1 and 2.
template<typename MatrixType>
MatrixType randomMatrixWithRealEivals(const int size)
{
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType diag = MatrixType::Zero(size, size);
  for (int i = 0; i < size; ++i) {
    diag(i, i) = Scalar(RealScalar(ei_random<int>(0,2)))
      + ei_random<Scalar>() * Scalar(RealScalar(0.01));
  }
  MatrixType A = MatrixType::Random(size, size);
  return A.inverse() * diag * A;
}

template <typename MatrixType, int IsComplex = NumTraits<typename ei_traits<MatrixType>::Scalar>::IsComplex>
struct randomMatrixWithImagEivals
{
  // Returns a matrix with eigenvalues clustered around 0 and +/- i.
  static MatrixType run(const int size);
};

// Partial specialization for real matrices
template<typename MatrixType>
struct randomMatrixWithImagEivals<MatrixType, 0>
{
  static MatrixType run(const int size)
  {
    typedef typename MatrixType::Scalar Scalar;
    MatrixType diag = MatrixType::Zero(size, size);
    int i = 0;
    while (i < size) {
      int randomInt = ei_random<int>(-1, 1);
      if (randomInt == 0 || i == size-1) {
        diag(i, i) = ei_random<Scalar>() * Scalar(0.01);
        ++i;
      } else {
        Scalar alpha = Scalar(randomInt) + ei_random<Scalar>() * Scalar(0.01);
        diag(i, i+1) = alpha;
        diag(i+1, i) = -alpha;
        i += 2;
      }
    }
    MatrixType A = MatrixType::Random(size, size);
    return A.inverse() * diag * A;
  }
};

// Partial specialization for complex matrices
template<typename MatrixType>
struct randomMatrixWithImagEivals<MatrixType, 1>
{
  static MatrixType run(const int size)
  {
    typedef typename MatrixType::Scalar Scalar;
    typedef typename MatrixType::RealScalar RealScalar;
    const Scalar imagUnit(0, 1);
    MatrixType diag = MatrixType::Zero(size, size);
    for (int i = 0; i < size; ++i) {
      diag(i, i) = Scalar(RealScalar(ei_random<int>(-1, 1))) * imagUnit
        + ei_random<Scalar>() * Scalar(RealScalar(0.01));
    }
    MatrixType A = MatrixType::Random(size, size);
    return A.inverse() * diag * A;
  }
};

template<typename MatrixType>
void testMatrixExponential(const MatrixType& A)
{
  typedef typename ei_traits<MatrixType>::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef std::complex<RealScalar> ComplexScalar;

  for (int i = 0; i < g_repeat; i++) {
    MatrixType expA1, expA2;
    ei_matrix_exponential(A, &expA1);
    ei_matrix_function(A, StdStemFunctions<ComplexScalar>::exp, &expA2);
    VERIFY_IS_APPROX(expA1, expA2);
  }
}

template<typename MatrixType>
void testHyperbolicFunctions(const MatrixType& A)
{
  for (int i = 0; i < g_repeat; i++) {
    MatrixType sinhA, coshA, expA;
    ei_matrix_sinh(A, &sinhA);
    ei_matrix_cosh(A, &coshA);
    ei_matrix_exponential(A, &expA);
    VERIFY_IS_APPROX(sinhA, (expA - expA.inverse())/2);
    VERIFY_IS_APPROX(coshA, (expA + expA.inverse())/2);
  }
}

template<typename MatrixType>
void testGonioFunctions(const MatrixType& A)
{
  typedef ei_traits<MatrixType> Traits;
  typedef typename Traits::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef std::complex<RealScalar> ComplexScalar;
  typedef Matrix<ComplexScalar, Traits::RowsAtCompileTime,
                 Traits::ColsAtCompileTime, MatrixType::Options> ComplexMatrix;

  ComplexScalar imagUnit(0,1);
  ComplexScalar two(2,0);

  for (int i = 0; i < g_repeat; i++) {
    ComplexMatrix Ac = A.template cast<ComplexScalar>();

    ComplexMatrix exp_iA;
    ei_matrix_exponential(imagUnit * Ac, &exp_iA);

    MatrixType sinA;
    ei_matrix_sin(A, &sinA);
    ComplexMatrix sinAc = sinA.template cast<ComplexScalar>();
    VERIFY_IS_APPROX(sinAc, (exp_iA - exp_iA.inverse()) / (two*imagUnit));

    MatrixType cosA;
    ei_matrix_cos(A, &cosA);
    ComplexMatrix cosAc = cosA.template cast<ComplexScalar>();
    VERIFY_IS_APPROX(cosAc, (exp_iA + exp_iA.inverse()) / 2);
  }
}

template<typename MatrixType>
void testMatrix(const MatrixType& A)
{
  testMatrixExponential(A);
  testHyperbolicFunctions(A);
  testGonioFunctions(A);
}

template<typename MatrixType>
void testMatrixType(const MatrixType& m)
{
  // Matrices with clustered eigenvalue lead to different code paths
  // in MatrixFunction.h and are thus useful for testing.

  const int size = m.rows();
  for (int i = 0; i < g_repeat; i++) {
    testMatrix(MatrixType::Random(size, size).eval());
    testMatrix(randomMatrixWithRealEivals<MatrixType>(size));
    testMatrix(randomMatrixWithImagEivals<MatrixType>::run(size));
  }
}

void test_matrix_function()
{
  CALL_SUBTEST_1(testMatrixType(Matrix<float,1,1>()));
  CALL_SUBTEST_2(testMatrixType(Matrix3cf()));
  CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8)));
  CALL_SUBTEST_4(testMatrixType(Matrix2d()));
  CALL_SUBTEST_5(testMatrixType(Matrix<double,5,5,RowMajor>()));
  CALL_SUBTEST_6(testMatrixType(Matrix4cd()));
  CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13)));
}
<|endoftext|>


<commit_before>/*
 * TI Voxel Lib component.
 *
 * Copyright (c) 2014 Texas Instruments Inc.
 */

#include "CameraSystem.h"

#include "SimpleOpt.h"
#include "Common.h"
#include "Logger.h"
#include "UVCStreamer.h"
#include <iomanip>
#include <fstream>

using namespace Voxel;

enum Options
{
  VENDOR_ID = 0,
  PRODUCT_ID = 1,
  SERIAL_NUMBER = 2,
  CREATE_PROFILE = 3,
  PARENT_PROFILE_ID = 4,
  PROFILE_ID = 5,
  SECTION = 6,
  PARAM_NAME = 7,
  PARAM_VALUE = 8,
  LIST_PROFILES = 9,
  REMOVE_PROFILE = 10,
  WRITE_TO_EEPROM = 11,
  SAVE_FILE_TO_HOST = 12,
};

Vector<CSimpleOpt::SOption> argumentSpecifications =
{
  { VENDOR_ID,        "-v", SO_REQ_SEP, "Vendor ID of the USB device (hexadecimal)"}, // Only worker count is needed here
  { PRODUCT_ID,       "-p", SO_REQ_SEP, "Comma separated list of Product IDs of the USB devices (hexadecimal)"},
  { SERIAL_NUMBER,    "-s", SO_REQ_SEP, "Serial number of the USB device (string)"},
  { CREATE_PROFILE,   "-c", SO_REQ_SEP, "Should create a new profile? If given, then name is to specified"},
  { PARENT_PROFILE_ID,"-d", SO_REQ_SEP, "Parent profile ID used while creating a new profile [default = -1]."},
  { PROFILE_ID,       "-i", SO_REQ_SEP, "ID of the camera profile"},
  { SECTION,          "-t", SO_REQ_SEP, "Name of the configuration section"},
  { PARAM_NAME,       "-n", SO_REQ_SEP, "Name of the parameter to read/write"},
  { PARAM_VALUE,      "-u", SO_REQ_SEP, "Value for the parameter. This will be written. If not given, then the parameter will be read."},
  { LIST_PROFILES,    "-l", SO_NONE,    "List all profiles for this camera"},
  { REMOVE_PROFILE,   "-r", SO_NONE,    "Remove profile selected with -i option"},
  { WRITE_TO_EEPROM,  "-w", SO_NONE,    "Write to EEPROM, the profile selected with -i option"},
  { SAVE_FILE_TO_HOST,"-z", SO_NONE,    "Save selected profile (present in EEPROM) to host"},
  SO_END_OF_OPTIONS
};

void help()
{
  std::cout << "CameraSystemConfigTest v1.0" << std::endl;

  CSimpleOpt::SOption *option = argumentSpecifications.data();

  while(option->nId >= 0)
  {
    std::cout << option->pszArg << " " << option->helpInfo << std::endl;
    option++;
  }
}

int main(int argc, char *argv[])
{
  CSimpleOpt s(argc, argv, argumentSpecifications);

  logger.setDefaultLogLevel(LOG_ERROR);

  uint16_t vid = 0;

  Vector<uint16_t> pids;
  String serialNumber;

  bool listProfiles = false;

  bool createProfile = false, removeProfile = false, writeToEEPROM = false, saveToHost = false;
  String profileName;
  int profileID = -1, parentProfileID = -1;

  bool readParam = true;
  String section, paramName, paramValue;

  char *endptr;
  Vector<String> splits;

  while (s.Next())
  {
    if (s.LastError() != SO_SUCCESS)
    {
      std::cout << s.GetLastErrorText(s.LastError()) << ": '" << s.OptionText() << "' (use -h to get command line help)" << std::endl;
      help();
      return -1;
    }

    //std::cout << s.OptionId() << ": " << s.OptionArg() << std::endl;

    Vector<String> splits;
    switch (s.OptionId())
    {
      case VENDOR_ID:
        vid = (uint16_t)strtol(s.OptionArg(), &endptr, 16);
        break;

      case PRODUCT_ID:
        split(s.OptionArg(), ',', splits);

        for(auto &s1: splits)
          pids.push_back((uint16_t)strtol(s1.c_str(), &endptr, 16));

        break;

      case SERIAL_NUMBER:
        serialNumber = s.OptionArg();
        break;

      case CREATE_PROFILE:
        createProfile = true;
        profileName = s.OptionArg();
        break;

      case PARENT_PROFILE_ID:
        parentProfileID = atoi(s.OptionArg());
        break;

      case PROFILE_ID:
        profileID = atoi(s.OptionArg());
        break;

      case SECTION:
        section = s.OptionArg();
        break;

      case PARAM_NAME:
        paramName = s.OptionArg();
        break;

      case PARAM_VALUE:
        readParam = false;
        paramValue = s.OptionArg();
        break;

      case LIST_PROFILES:
        listProfiles = true;
        break;

      case REMOVE_PROFILE:
        removeProfile = true;
        break;

      case WRITE_TO_EEPROM:
        writeToEEPROM = true;
        break;

      case SAVE_FILE_TO_HOST:
        saveToHost = true;
        break;

      default:
        help();
        break;
    };
  }

  if(vid == 0 || pids.size() == 0 || pids[0] == 0)
  {
    logger(LOG_ERROR) << "Required argument missing." << std::endl;
    help();
    return -1;
  }

  CameraSystem sys;

  // Get all valid detected devices
  const Vector<DevicePtr> &devices = sys.scan();

  DevicePtr toConnect;

  std::cout << "Detected devices: " << std::endl;
  for(auto &d: devices)
  {
    std::cout << d->id() << std::endl;

    if(d->interfaceID() == Device::USB)
    {
      USBDevice &usb = (USBDevice &)*d;

      if(usb.vendorID() == vid && (serialNumber.size() == 0 || usb.serialNumber() == serialNumber))
      {
        for(auto pid: pids)
          if(usb.productID() == pid)
            toConnect = d;
      }
    }
  }

  if(!toConnect)
  {
    logger(LOG_ERROR) << "No valid device found for the specified VID:PID:serialnumber" << std::endl;
    return -1;
  }

  DepthCameraPtr depthCamera = sys.connect(toConnect);

  if(!depthCamera)
  {
    logger(LOG_ERROR) << "Could not load depth camera for device " << toConnect->id() << std::endl;
    return -1;
  }

  if(!depthCamera->isInitialized())
  {
    logger(LOG_ERROR) << "Depth camera not initialized for device " << toConnect->id() << std::endl;
    return -1;
  }

  std::cout << "Successfully loaded depth camera for device " << toConnect->id() << std::endl;

  if(listProfiles)
  {
    const Map<int, String> &profiles = depthCamera->getCameraProfileNames();

    for(auto &p: profiles)
    {
      std::cout << p.first << ", " << p.second;

      ConfigurationFile *c = depthCamera->configFile.getCameraProfile(p.first);

      if(c && c->getLocation() == ConfigurationFile::IN_CAMERA)
        std::cout << " (HW)";

      std::cout << std::endl;
    }

    return 0;
  }

  int id;

  if(createProfile)
  {
    id = depthCamera->addCameraProfile(profileName, parentProfileID);
    if(id < 0)
    {
      logger(LOG_ERROR) << "Failed to create new camera profile with name '" << profileName << "' and parent = " << parentProfileID << std::endl;
      return -1;
    }

    std::cout << "Created profile with id = " << id << std::endl;
  }
  else
  {
    id = profileID;
  }

  ConfigurationFile *configFile = depthCamera->configFile.getCameraProfile(id);

  if(!configFile)
  {
    logger(LOG_ERROR) << "Could not find config file for id = " << id << std::endl;
    return -1;
  }

  bool needToWrite = false;
  if(section.size() == 0 || paramName.size() == 0 || (!readParam && paramValue.size() == 0))
  {
    logger(LOG_INFO) << "One of the requirement parameter to read/write parameter is missing." << std::endl;
  }
  else
  {
    if(readParam)
    {
      if(configFile->isPresent(section, paramName))
        std::cout << "Param value for section = " << section << ", name = " << paramName
          << ", value = " << configFile->get(section, paramName) << std::endl;
      else
        logger(LOG_ERROR) << "Param not found, section = " << section << ", name = " << paramName << std::endl;
    }
    else
    {
      if(!configFile->set(section, paramName, paramValue))
      {
        std::cout << "Failed to set parameter, section = " << section << ", name = " << paramName
        << ", value = " << paramValue << std::endl;
      }
      else
      {
        std::cout << "Successfully set parameter, section = " << section << ", name = " << paramName
        << ", value = " << paramValue << std::endl;
        needToWrite = true;
      }
    }
  }

  if(needToWrite)
  {
    if(configFile->getLocation() == ConfigurationFile::IN_CAMERA)
    {
      if(!depthCamera->configFile.writeToHardware())
      {
        logger(LOG_ERROR) << "Failed to save configuration for id = " << id << std::endl;
        return -1;
      }
    }
    else if(!configFile->write())
    {
      logger(LOG_ERROR) << "Failed to save configuration for id = " << id << std::endl;
      return -1;
    }
    return 0;
  }

  if(writeToEEPROM)
  {
    if(!depthCamera->saveCameraProfileToHardware(id))
    {
      logger(LOG_ERROR) << "Failed to save configuration for id = " << id << " to EEPROM." << std::endl;
      return -1;
    }

    std::cout << "Profile saved to hardware with id = " << id << std::endl;
    return 0;
  }

  if(saveToHost)
  {
    ConfigurationFile *config = depthCamera->configFile.getCameraProfile(id);

    if(!config)
    {
      logger(LOG_ERROR) << "Failed to get configuration for id = " << id << "." << std::endl;
      return -1;
    }

    if(!config->write())
    {
      logger(LOG_ERROR) << "Failed to save configuration with id = " << id << " on host." << std::endl;
      return -1;
    }

    std::cout << "Profile saved to host with id = " << id << " to file '" << config->getFileName() << "'" << std::endl;
    return 0;
  }

  if(removeProfile)
  {
    char ch;
    std::cout << "Are you sure you want to remove profile with id '" << id << "' [y/n]? ";
    std::cin >> ch;

    if(ch == 'y' || ch == 'Y')
    {
      if(!depthCamera->configFile.removeCameraProfile(id))
      {
        std::cout << "Failed to remove camera profile '" << id << "'" << std::endl;
        return -1;
      }
      else
        std::cout << "Successfully removed camera profile '" << id << "'" << std::endl;
    }
    return 0;
  }

  return 0;
}<commit_msg>Support for negative numbered values by using single or double quoted values<commit_after>/*
 * TI Voxel Lib component.
 *
 * Copyright (c) 2014 Texas Instruments Inc.
 */

#include "CameraSystem.h"

#include "SimpleOpt.h"
#include "Common.h"
#include "Logger.h"
#include "UVCStreamer.h"
#include <iomanip>
#include <fstream>

using namespace Voxel;

enum Options
{
  VENDOR_ID = 0,
  PRODUCT_ID = 1,
  SERIAL_NUMBER = 2,
  CREATE_PROFILE = 3,
  PARENT_PROFILE_ID = 4,
  PROFILE_ID = 5,
  SECTION = 6,
  PARAM_NAME = 7,
  PARAM_VALUE = 8,
  LIST_PROFILES = 9,
  REMOVE_PROFILE = 10,
  WRITE_TO_EEPROM = 11,
  SAVE_FILE_TO_HOST = 12,
};

Vector<CSimpleOpt::SOption> argumentSpecifications =
{
  { VENDOR_ID,        "-v", SO_REQ_SEP, "Vendor ID of the USB device (hexadecimal)"}, // Only worker count is needed here
  { PRODUCT_ID,       "-p", SO_REQ_SEP, "Comma separated list of Product IDs of the USB devices (hexadecimal)"},
  { SERIAL_NUMBER,    "-s", SO_REQ_SEP, "Serial number of the USB device (string)"},
  { CREATE_PROFILE,   "-c", SO_REQ_SEP, "Should create a new profile? If given, then name is to specified"},
  { PARENT_PROFILE_ID,"-d", SO_REQ_SEP, "Parent profile ID used while creating a new profile [default = -1]."},
  { PROFILE_ID,       "-i", SO_REQ_SEP, "ID of the camera profile"},
  { SECTION,          "-t", SO_REQ_SEP, "Name of the configuration section"},
  { PARAM_NAME,       "-n", SO_REQ_SEP, "Name of the parameter to read/write"},
  { PARAM_VALUE,      "-u", SO_REQ_SEP, "Value for the parameter. This will be written. If not given, then the parameter will be read."},
  { LIST_PROFILES,    "-l", SO_NONE,    "List all profiles for this camera"},
  { REMOVE_PROFILE,   "-r", SO_NONE,    "Remove profile selected with -i option"},
  { WRITE_TO_EEPROM,  "-w", SO_NONE,    "Write to EEPROM, the profile selected with -i option"},
  { SAVE_FILE_TO_HOST,"-z", SO_NONE,    "Save selected profile (present in EEPROM) to host"},
  SO_END_OF_OPTIONS
};

void help()
{
  std::cout << "CameraSystemConfigTest v1.0" << std::endl;

  CSimpleOpt::SOption *option = argumentSpecifications.data();

  while(option->nId >= 0)
  {
    std::cout << option->pszArg << " " << option->helpInfo << std::endl;
    option++;
  }
}

int main(int argc, char *argv[])
{
  CSimpleOpt s(argc, argv, argumentSpecifications);

  logger.setDefaultLogLevel(LOG_ERROR);

  uint16_t vid = 0;

  Vector<uint16_t> pids;
  String serialNumber;

  bool listProfiles = false;

  bool createProfile = false, removeProfile = false, writeToEEPROM = false, saveToHost = false;
  String profileName;
  int profileID = -1, parentProfileID = -1;

  bool readParam = true;
  String section, paramName, paramValue;

  char *endptr;
  Vector<String> splits;

  while (s.Next())
  {
    if (s.LastError() != SO_SUCCESS)
    {
      std::cout << s.GetLastErrorText(s.LastError()) << ": '" << s.OptionText() << "' (use -h to get command line help)" << std::endl;
      help();
      return -1;
    }

    //std::cout << s.OptionId() << ": " << s.OptionArg() << std::endl;

    Vector<String> splits;
    switch (s.OptionId())
    {
      case VENDOR_ID:
        vid = (uint16_t)strtol(s.OptionArg(), &endptr, 16);
        break;

      case PRODUCT_ID:
        split(s.OptionArg(), ',', splits);

        for(auto &s1: splits)
          pids.push_back((uint16_t)strtol(s1.c_str(), &endptr, 16));

        break;

      case SERIAL_NUMBER:
        serialNumber = s.OptionArg();
        break;

      case CREATE_PROFILE:
        createProfile = true;
        profileName = s.OptionArg();
        break;

      case PARENT_PROFILE_ID:
        parentProfileID = atoi(s.OptionArg());
        break;

      case PROFILE_ID:
        profileID = atoi(s.OptionArg());
        break;

      case SECTION:
        section = s.OptionArg();
        break;

      case PARAM_NAME:
        paramName = s.OptionArg();
        break;

      case PARAM_VALUE:
        readParam = false;
        paramValue = s.OptionArg();

        if(paramValue.size() > 0 &&
            ((paramValue[0] == '\'' && paramValue[paramValue.size() - 1] == '\'') ||
            (paramValue[0] == '"' && paramValue[paramValue.size() - 1] == '"')))
          paramValue = paramValue.substr(1, paramValue.size() - 2);

        break;

      case LIST_PROFILES:
        listProfiles = true;
        break;

      case REMOVE_PROFILE:
        removeProfile = true;
        break;

      case WRITE_TO_EEPROM:
        writeToEEPROM = true;
        break;

      case SAVE_FILE_TO_HOST:
        saveToHost = true;
        break;

      default:
        help();
        break;
    };
  }

  if(vid == 0 || pids.size() == 0 || pids[0] == 0)
  {
    logger(LOG_ERROR) << "Required argument missing." << std::endl;
    help();
    return -1;
  }

  CameraSystem sys;

  // Get all valid detected devices
  const Vector<DevicePtr> &devices = sys.scan();

  DevicePtr toConnect;

  std::cout << "Detected devices: " << std::endl;
  for(auto &d: devices)
  {
    std::cout << d->id() << std::endl;

    if(d->interfaceID() == Device::USB)
    {
      USBDevice &usb = (USBDevice &)*d;

      if(usb.vendorID() == vid && (serialNumber.size() == 0 || usb.serialNumber() == serialNumber))
      {
        for(auto pid: pids)
          if(usb.productID() == pid)
            toConnect = d;
      }
    }
  }

  if(!toConnect)
  {
    logger(LOG_ERROR) << "No valid device found for the specified VID:PID:serialnumber" << std::endl;
    return -1;
  }

  DepthCameraPtr depthCamera = sys.connect(toConnect);

  if(!depthCamera)
  {
    logger(LOG_ERROR) << "Could not load depth camera for device " << toConnect->id() << std::endl;
    return -1;
  }

  if(!depthCamera->isInitialized())
  {
    logger(LOG_ERROR) << "Depth camera not initialized for device " << toConnect->id() << std::endl;
    return -1;
  }

  std::cout << "Successfully loaded depth camera for device " << toConnect->id() << std::endl;

  if(listProfiles)
  {
    const Map<int, String> &profiles = depthCamera->getCameraProfileNames();

    for(auto &p: profiles)
    {
      std::cout << p.first << ", " << p.second;

      ConfigurationFile *c = depthCamera->configFile.getCameraProfile(p.first);

      if(c && c->getLocation() == ConfigurationFile::IN_CAMERA)
        std::cout << " (HW)";

      std::cout << std::endl;
    }

    return 0;
  }

  int id;

  if(createProfile)
  {
    id = depthCamera->addCameraProfile(profileName, parentProfileID);
    if(id < 0)
    {
      logger(LOG_ERROR) << "Failed to create new camera profile with name '" << profileName << "' and parent = " << parentProfileID << std::endl;
      return -1;
    }

    std::cout << "Created profile with id = " << id << std::endl;
  }
  else
  {
    id = profileID;
  }

  ConfigurationFile *configFile = depthCamera->configFile.getCameraProfile(id);

  if(!configFile)
  {
    logger(LOG_ERROR) << "Could not find config file for id = " << id << std::endl;
    return -1;
  }

  bool needToWrite = false;
  if(section.size() == 0 || paramName.size() == 0 || (!readParam && paramValue.size() == 0))
  {
    logger(LOG_INFO) << "One of the requirement parameter to read/write parameter is missing." << std::endl;
  }
  else
  {
    if(readParam)
    {
      if(configFile->isPresent(section, paramName))
        std::cout << "Param value for section = " << section << ", name = " << paramName
          << ", value = " << configFile->get(section, paramName) << std::endl;
      else
        logger(LOG_ERROR) << "Param not found, section = " << section << ", name = " << paramName << std::endl;
    }
    else
    {
      if(!configFile->set(section, paramName, paramValue))
      {
        std::cout << "Failed to set parameter, section = " << section << ", name = " << paramName
        << ", value = " << paramValue << std::endl;
      }
      else
      {
        std::cout << "Successfully set parameter, section = " << section << ", name = " << paramName
        << ", value = " << paramValue << std::endl;
        needToWrite = true;
      }
    }
  }

  if(needToWrite)
  {
    if(configFile->getLocation() == ConfigurationFile::IN_CAMERA)
    {
      if(!depthCamera->configFile.writeToHardware())
      {
        logger(LOG_ERROR) << "Failed to save configuration for id = " << id << std::endl;
        return -1;
      }
    }
    else if(!configFile->write())
    {
      logger(LOG_ERROR) << "Failed to save configuration for id = " << id << std::endl;
      return -1;
    }
    return 0;
  }

  if(writeToEEPROM)
  {
    if(!depthCamera->saveCameraProfileToHardware(id))
    {
      logger(LOG_ERROR) << "Failed to save configuration for id = " << id << " to EEPROM." << std::endl;
      return -1;
    }

    std::cout << "Profile saved to hardware with id = " << id << std::endl;
    return 0;
  }

  if(saveToHost)
  {
    ConfigurationFile *config = depthCamera->configFile.getCameraProfile(id);

    if(!config)
    {
      logger(LOG_ERROR) << "Failed to get configuration for id = " << id << "." << std::endl;
      return -1;
    }

    if(!config->write())
    {
      logger(LOG_ERROR) << "Failed to save configuration with id = " << id << " on host." << std::endl;
      return -1;
    }

    std::cout << "Profile saved to host with id = " << id << " to file '" << config->getFileName() << "'" << std::endl;
    return 0;
  }

  if(removeProfile)
  {
    char ch;
    std::cout << "Are you sure you want to remove profile with id '" << id << "' [y/n]? ";
    std::cin >> ch;

    if(ch == 'y' || ch == 'Y')
    {
      if(!depthCamera->configFile.removeCameraProfile(id))
      {
        std::cout << "Failed to remove camera profile '" << id << "'" << std::endl;
        return -1;
      }
      else
        std::cout << "Successfully removed camera profile '" << id << "'" << std::endl;
    }
    return 0;
  }

  return 0;
}<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/multi_process_lock.h"

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include "base/eintr_wrapper.h"
#include "base/logging.h"

class MultiProcessLockLinux : public MultiProcessLock {
 public:
  explicit MultiProcessLockLinux(const std::string& name)
      : name_(name), fd_(-1) { }

  virtual ~MultiProcessLockLinux() {
    if (fd_ != -1) {
      Unlock();
    }
  }

  virtual bool TryLock() {
    if (fd_ != -1) {
      DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
      return true;
    }

    if (name_.length() > MULTI_PROCESS_LOCK_NAME_MAX_LEN) {
      LOG(ERROR) << "Socket name too long - " << name_;
      return false;
    }

    struct sockaddr_un address;

    // +1 for terminator, +1 for 0 in position 0 that makes it an
    // abstract named socket.
    // If this assert fails it is because sockaddr_un.sun_path size has been
    // redefined and MULTI_PROCESS_LOCK_NAME_MAX_LEN can change accordingly.
    COMPILE_ASSERT(sizeof(address.sun_path)
        == MULTI_PROCESS_LOCK_NAME_MAX_LEN + 2, sun_path_size_changed);

    memset(&address, 0, sizeof(address));
    int print_length = snprintf(&address.sun_path[1],
                                MULTI_PROCESS_LOCK_NAME_MAX_LEN + 1,
                                "%s", name_.c_str());

    if (print_length < 0 ||
        print_length > static_cast<int>(MULTI_PROCESS_LOCK_NAME_MAX_LEN)) {
      PLOG(ERROR) << "Couldn't create sun_path - " << name_;
      return false;
    }

    // Must set the first character of the path to something non-zero
    // before we call SUN_LEN which depends on strcpy working.
    address.sun_path[0] = '@';
    size_t length = SUN_LEN(&address);

    // Reset the first character of the path back to zero so that
    // bind returns an abstract name socket.
    address.sun_path[0] = 0;
    address.sun_family = AF_LOCAL;

    int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (socket_fd < 0) {
      PLOG(ERROR) << "Couldn't create socket - " << name_;
      return false;
    }

    if (bind(socket_fd,
             reinterpret_cast<sockaddr *>(&address),
             length) == 0) {
      fd_ = socket_fd;
      return true;
    } else {
      PLOG(ERROR) << "Couldn't bind socket - "
                  << &(address.sun_path[1])
                  << " Length: " << length;
      if (HANDLE_EINTR(close(socket_fd)) < 0) {
        PLOG(ERROR) << "close";
      }
      return false;
    }
  }

  virtual void Unlock() {
    if (fd_ == -1) {
      DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
      return;
    }
    if (HANDLE_EINTR(close(fd_)) < 0) {
      PLOG(ERROR) << "close";
    }
    fd_ = -1;
  }

 private:
  std::string name_;
  int fd_;
  DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
};

MultiProcessLock* MultiProcessLock::Create(const std::string &name) {
  return new MultiProcessLockLinux(name);
}
<commit_msg>add missing header.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/multi_process_lock.h"

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include "base/eintr_wrapper.h"
#include "base/logging.h"

class MultiProcessLockLinux : public MultiProcessLock {
 public:
  explicit MultiProcessLockLinux(const std::string& name)
      : name_(name), fd_(-1) { }

  virtual ~MultiProcessLockLinux() {
    if (fd_ != -1) {
      Unlock();
    }
  }

  virtual bool TryLock() {
    if (fd_ != -1) {
      DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
      return true;
    }

    if (name_.length() > MULTI_PROCESS_LOCK_NAME_MAX_LEN) {
      LOG(ERROR) << "Socket name too long - " << name_;
      return false;
    }

    struct sockaddr_un address;

    // +1 for terminator, +1 for 0 in position 0 that makes it an
    // abstract named socket.
    // If this assert fails it is because sockaddr_un.sun_path size has been
    // redefined and MULTI_PROCESS_LOCK_NAME_MAX_LEN can change accordingly.
    COMPILE_ASSERT(sizeof(address.sun_path)
        == MULTI_PROCESS_LOCK_NAME_MAX_LEN + 2, sun_path_size_changed);

    memset(&address, 0, sizeof(address));
    int print_length = snprintf(&address.sun_path[1],
                                MULTI_PROCESS_LOCK_NAME_MAX_LEN + 1,
                                "%s", name_.c_str());

    if (print_length < 0 ||
        print_length > static_cast<int>(MULTI_PROCESS_LOCK_NAME_MAX_LEN)) {
      PLOG(ERROR) << "Couldn't create sun_path - " << name_;
      return false;
    }

    // Must set the first character of the path to something non-zero
    // before we call SUN_LEN which depends on strcpy working.
    address.sun_path[0] = '@';
    size_t length = SUN_LEN(&address);

    // Reset the first character of the path back to zero so that
    // bind returns an abstract name socket.
    address.sun_path[0] = 0;
    address.sun_family = AF_LOCAL;

    int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (socket_fd < 0) {
      PLOG(ERROR) << "Couldn't create socket - " << name_;
      return false;
    }

    if (bind(socket_fd,
             reinterpret_cast<sockaddr *>(&address),
             length) == 0) {
      fd_ = socket_fd;
      return true;
    } else {
      PLOG(ERROR) << "Couldn't bind socket - "
                  << &(address.sun_path[1])
                  << " Length: " << length;
      if (HANDLE_EINTR(close(socket_fd)) < 0) {
        PLOG(ERROR) << "close";
      }
      return false;
    }
  }

  virtual void Unlock() {
    if (fd_ == -1) {
      DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
      return;
    }
    if (HANDLE_EINTR(close(fd_)) < 0) {
      PLOG(ERROR) << "close";
    }
    fd_ = -1;
  }

 private:
  std::string name_;
  int fd_;
  DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
};

MultiProcessLock* MultiProcessLock::Create(const std::string &name) {
  return new MultiProcessLockLinux(name);
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sigcache.h"

#include "memusage.h"
#include "pubkey.h"
#include "random.h"
#include "uint256.h"
#include "util.h"

#include <boost/thread.hpp>
#include <boost/unordered_set.hpp>

namespace {

/**
 * We're hashing a nonce into the entries themselves, so we don't need extra
 * blinding in the set hash computation.
 */
class CSignatureCacheHasher
{
public:
    size_t operator()(const uint256& key) const {
        return key.GetCheapHash();
    }
};

/**
 * Valid signature cache, to avoid doing expensive ECDSA signature checking
 * twice for every transaction (once when accepted into memory pool, and
 * again when accepted into the block chain)
 */
class CSignatureCache
{
private:
     //! Entries are SHA256(nonce || signature hash || public key || signature):
    uint256 nonce;
    typedef boost::unordered_set<uint256, CSignatureCacheHasher> map_type;
    map_type setValid;
    boost::shared_mutex cs_sigcache;

public:
    CSignatureCache()
    {
        GetRandBytes(nonce.begin(), 32);
    }

    void
    ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
    {
        CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
    }

    bool
    Get(const uint256& entry)
    {
        boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
        return setValid.count(entry);
    }

    void Set(const uint256& entry)
    {
        size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
        if (nMaxCacheSize <= 0) return;

        boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
        while (memusage::DynamicUsage(setValid) > nMaxCacheSize)
        {
            map_type::size_type s = GetRand(setValid.bucket_count());
            map_type::local_iterator it = setValid.begin(s);
            if (it != setValid.end(s)) {
                setValid.erase(*it);
            }
        }

        setValid.insert(entry);
    }
};

}

bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
    static CSignatureCache signatureCache;

    uint256 entry;
    signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey);

    if (signatureCache.Get(entry))
        return true;

    if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
        return false;

    if (store)
        signatureCache.Set(entry);
    return true;
}
<commit_msg>Evict sigcache entries that are seen in a block<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sigcache.h"

#include "memusage.h"
#include "pubkey.h"
#include "random.h"
#include "uint256.h"
#include "util.h"

#include <boost/thread.hpp>
#include <boost/unordered_set.hpp>

namespace {

/**
 * We're hashing a nonce into the entries themselves, so we don't need extra
 * blinding in the set hash computation.
 */
class CSignatureCacheHasher
{
public:
    size_t operator()(const uint256& key) const {
        return key.GetCheapHash();
    }
};

/**
 * Valid signature cache, to avoid doing expensive ECDSA signature checking
 * twice for every transaction (once when accepted into memory pool, and
 * again when accepted into the block chain)
 */
class CSignatureCache
{
private:
     //! Entries are SHA256(nonce || signature hash || public key || signature):
    uint256 nonce;
    typedef boost::unordered_set<uint256, CSignatureCacheHasher> map_type;
    map_type setValid;
    boost::shared_mutex cs_sigcache;

public:
    CSignatureCache()
    {
        GetRandBytes(nonce.begin(), 32);
    }

    void
    ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
    {
        CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
    }

    bool
    Get(const uint256& entry)
    {
        boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
        return setValid.count(entry);
    }

    void Erase(const uint256& entry)
    {
        boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
        setValid.erase(entry);
    }

    void Set(const uint256& entry)
    {
        size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
        if (nMaxCacheSize <= 0) return;

        boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
        while (memusage::DynamicUsage(setValid) > nMaxCacheSize)
        {
            map_type::size_type s = GetRand(setValid.bucket_count());
            map_type::local_iterator it = setValid.begin(s);
            if (it != setValid.end(s)) {
                setValid.erase(*it);
            }
        }

        setValid.insert(entry);
    }
};

}

bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
    static CSignatureCache signatureCache;

    uint256 entry;
    signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey);

    if (signatureCache.Get(entry)) {
        if (!store) {
            signatureCache.Erase(entry);
        }
        return true;
    }

    if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
        return false;

    if (store) {
        signatureCache.Set(entry);
    }
    return true;
}
<|endoftext|>


<commit_before>/*-
 * Copyright (C) 2012  University Radio York Computing Team
 *
 * This file is a part of playslave.
 *
 * playslave is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * playslave is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * playslave; if not, write to the Free Software Foundation, Inc., 51 Franklin
 * Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#define _POSIX_C_SOURCE 200809

/**  INCLUDES  ****************************************************************/

#include <memory>
#include <sstream>
#include <vector>

#include <cstdarg>		/* gate_state */
#include <cstdbool>		/* bool */
#include <cstdint>
#include <cstdlib>
#include <cstring>

#include <thread>
#include <chrono>

#ifdef WIN32
struct timespec
{
	time_t tv_sec;
	long tv_nsec;
};
#include <Winsock2.h>
#else
#include <time.h>		/* struct timespec */
#endif

#include "cuppa/cmd.h"		/* struct cmd, check_commands */
#include "cuppa/io.h"           /* response */

#include "audio.h"
#include "constants.h"
#include "messages.h"
#include "player.h"

/* This should be long enough to hold all the state names above separated with
 * spaces and null-terminated.
 */
#define STATE_NAME_BUF 256

/* Names of the states in enum state. */
const char	STATES[NUM_STATES][WORD_LEN] = {
	"Void",
	"Ejct",
	"Stop",
	"Play",
	"Quit",
};

enum state	GEND = S_VOID;

player::player(int device)
{
	this->cstate = S_EJCT;
	this->device = device;
	this->au = nullptr;
}

void
player::main_loop()
{
	enum error	err = E_OK;

	/* Set of commands that can be performed on the player. */
	command_set PLAYER_CMDS = {
		/* Nullary commands */
		{ "play", [&](const std::vector<std::string> &words) { return this->cmd_play(); } },
		{ "stop", [&](const std::vector<std::string> &words) { return this->cmd_stop(); } },
		{ "ejct", [&](const std::vector<std::string> &words) { return this->cmd_ejct(); } },
		{ "quit", [&](const std::vector<std::string> &words) { return this->cmd_quit(); } },
		/* Unary commands */
		{ "load", [&](const std::vector<std::string> &words) { return this->cmd_load(words[1]); } },
		{ "seek", [&](const std::vector<std::string> &words) { return this->cmd_load(words[1]); } }
	};

	response(R_OHAI, "%s", MSG_OHAI);	/* Say hello */
	while (state() != S_QUIT) {
		/*
		 * Possible Improvement: separate command checking and player
		 * updating into two threads.  Player updating is quite
		 * intensive and thus impairs the command checking latency.
		 * Do this if it doesn't make the code too complex.
		 */
		err = check_commands(PLAYER_CMDS);
		/* TODO: Check to see if err was fatal */
		loop_iter();

		std::this_thread::sleep_for(std::chrono::nanoseconds(LOOP_NSECS));
	}
	response(R_TTFN, "%s", MSG_TTFN);	/* Wave goodbye */
}

bool
player::cmd_ejct()
{
	bool valid = gate_state(S_STOP, S_PLAY, GEND);
	if (valid) {
		this->au = nullptr;
		set_state(S_EJCT);
		this->ptime = 0;
	}
	return valid;
}

bool
player::cmd_play()
{
	bool valid = gate_state(S_STOP, GEND) && (this->au != nullptr);
	if (valid) {
		this->au->start();
		set_state(S_PLAY);
	}
	return valid;
}

bool
player::cmd_quit()
{
	cmd_ejct();
	set_state(S_QUIT);

	return true; // Always a valid command.
}

bool
player::cmd_stop()
{
	bool valid = gate_state(S_PLAY, GEND);
	if (valid) {
		this->au->stop();
	}
	return valid;
}

bool
player::cmd_load(const std::string &filename)
{
	try {
		this->au = std::unique_ptr<audio>(new audio(filename, this->device));
		dbug("loaded %s", filename);
		set_state(S_STOP);
	}
	catch (enum error) {
		cmd_ejct();
	}

	return true; // Always a valid command.
}

bool
player::cmd_seek(const std::string &time_str)
{
	/* TODO: proper overflow checking */

	std::istringstream is(time_str);
	uint64_t time;
	std::string rest;
	is >> time >> rest;

	if (rest == "s" || rest == "sec") {
		time *= USECS_IN_SEC;
	}

	/* Weed out any unwanted states */
	bool valid = gate_state(S_PLAY, S_STOP, GEND);
	if (valid) {
		enum state current_state = this->cstate;

		cmd_stop(); // We need the player engine stopped in order to seek
		this->au->seek_usec(time);
		if (current_state == S_PLAY) {
			// If we were playing before we'd ideally like to resume
			cmd_play();
		}
	}

	return valid;
}

enum state
player::state()
{
	return this->cstate;
}

/* Performs an iteration of the player update loop. */
void
player::loop_iter()
{
	if (this->cstate == S_PLAY) {
		if (this->au->halted()) {
			cmd_ejct();
		} else {
			/* Send a time pulse upstream every TIME_USECS usecs */
			uint64_t time = this->au->usec();
			if (time / TIME_USECS > this->ptime / TIME_USECS) {
				response(R_TIME, "%u", time);
			}
			this->ptime = time;
		}
	}
	if (this->cstate == S_PLAY || this->cstate == S_STOP) {
		this->au->decode();
	}
}

/* Throws an error if the current state is not in the state set provided by
 * argument s1 and subsequent arguments up to 'GEND'.
 *
 * As a variadic function, the argument list MUST be terminated with 'GEND'.
 */
bool
player::gate_state(enum state s1,...)
{
	va_list		ap;
	int		i;
	enum error	err = E_OK;
	bool		in_state = false;

	va_start(ap, s1);
	for (i = (int)s1; !in_state && i != (int)GEND; i = va_arg(ap, int)) {
		if ((int)this->cstate == i) {
			in_state = true;
		}
	}
	va_end(ap);

	return in_state;
}

/* Sets the player state and honks accordingly. */
void
player::set_state(enum state state)
{
	enum state pstate = this->cstate;

	this->cstate = state;

	response(R_STAT, "%s %s", STATES[pstate], STATES[state]);
}
<commit_msg>Tidy up command words type.<commit_after>/*-
 * Copyright (C) 2012  University Radio York Computing Team
 *
 * This file is a part of playslave.
 *
 * playslave is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * playslave is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * playslave; if not, write to the Free Software Foundation, Inc., 51 Franklin
 * Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#define _POSIX_C_SOURCE 200809

/**  INCLUDES  ****************************************************************/

#include <memory>
#include <sstream>
#include <vector>

#include <cstdarg>		/* gate_state */
#include <cstdbool>		/* bool */
#include <cstdint>
#include <cstdlib>
#include <cstring>

#include <thread>
#include <chrono>

#ifdef WIN32
struct timespec
{
	time_t tv_sec;
	long tv_nsec;
};
#include <Winsock2.h>
#else
#include <time.h>		/* struct timespec */
#endif

#include "cuppa/cmd.h"		/* struct cmd, check_commands */
#include "cuppa/io.h"           /* response */

#include "audio.h"
#include "constants.h"
#include "messages.h"
#include "player.h"

/* This should be long enough to hold all the state names above separated with
 * spaces and null-terminated.
 */
#define STATE_NAME_BUF 256

/* Names of the states in enum state. */
const char	STATES[NUM_STATES][WORD_LEN] = {
	"Void",
	"Ejct",
	"Stop",
	"Play",
	"Quit",
};

enum state	GEND = S_VOID;

player::player(int device)
{
	this->cstate = S_EJCT;
	this->device = device;
	this->au = nullptr;
}

void
player::main_loop()
{
	enum error	err = E_OK;

	/* Set of commands that can be performed on the player. */
	command_set PLAYER_CMDS = {
		/* Nullary commands */
		{ "play", [&](const cmd_words &) { return this->cmd_play(); } },
		{ "stop", [&](const cmd_words &) { return this->cmd_stop(); } },
		{ "ejct", [&](const cmd_words &) { return this->cmd_ejct(); } },
		{ "quit", [&](const cmd_words &) { return this->cmd_quit(); } },
		/* Unary commands */
		{ "load", [&](const cmd_words &words) { return this->cmd_load(words[1]); } },
		{ "seek", [&](const cmd_words &words) { return this->cmd_load(words[1]); } }
	};

	response(R_OHAI, "%s", MSG_OHAI);	/* Say hello */
	while (state() != S_QUIT) {
		/*
		 * Possible Improvement: separate command checking and player
		 * updating into two threads.  Player updating is quite
		 * intensive and thus impairs the command checking latency.
		 * Do this if it doesn't make the code too complex.
		 */
		err = check_commands(PLAYER_CMDS);
		/* TODO: Check to see if err was fatal */
		loop_iter();

		std::this_thread::sleep_for(std::chrono::nanoseconds(LOOP_NSECS));
	}
	response(R_TTFN, "%s", MSG_TTFN);	/* Wave goodbye */
}

bool
player::cmd_ejct()
{
	bool valid = gate_state(S_STOP, S_PLAY, GEND);
	if (valid) {
		this->au = nullptr;
		set_state(S_EJCT);
		this->ptime = 0;
	}
	return valid;
}

bool
player::cmd_play()
{
	bool valid = gate_state(S_STOP, GEND) && (this->au != nullptr);
	if (valid) {
		this->au->start();
		set_state(S_PLAY);
	}
	return valid;
}

bool
player::cmd_quit()
{
	cmd_ejct();
	set_state(S_QUIT);

	return true; // Always a valid command.
}

bool
player::cmd_stop()
{
	bool valid = gate_state(S_PLAY, GEND);
	if (valid) {
		this->au->stop();
	}
	return valid;
}

bool
player::cmd_load(const std::string &filename)
{
	try {
		this->au = std::unique_ptr<audio>(new audio(filename, this->device));
		dbug("loaded %s", filename);
		set_state(S_STOP);
	}
	catch (enum error) {
		cmd_ejct();
	}

	return true; // Always a valid command.
}

bool
player::cmd_seek(const std::string &time_str)
{
	/* TODO: proper overflow checking */

	std::istringstream is(time_str);
	uint64_t time;
	std::string rest;
	is >> time >> rest;

	if (rest == "s" || rest == "sec") {
		time *= USECS_IN_SEC;
	}

	/* Weed out any unwanted states */
	bool valid = gate_state(S_PLAY, S_STOP, GEND);
	if (valid) {
		enum state current_state = this->cstate;

		cmd_stop(); // We need the player engine stopped in order to seek
		this->au->seek_usec(time);
		if (current_state == S_PLAY) {
			// If we were playing before we'd ideally like to resume
			cmd_play();
		}
	}

	return valid;
}

enum state
player::state()
{
	return this->cstate;
}

/* Performs an iteration of the player update loop. */
void
player::loop_iter()
{
	if (this->cstate == S_PLAY) {
		if (this->au->halted()) {
			cmd_ejct();
		} else {
			/* Send a time pulse upstream every TIME_USECS usecs */
			uint64_t time = this->au->usec();
			if (time / TIME_USECS > this->ptime / TIME_USECS) {
				response(R_TIME, "%u", time);
			}
			this->ptime = time;
		}
	}
	if (this->cstate == S_PLAY || this->cstate == S_STOP) {
		this->au->decode();
	}
}

/* Throws an error if the current state is not in the state set provided by
 * argument s1 and subsequent arguments up to 'GEND'.
 *
 * As a variadic function, the argument list MUST be terminated with 'GEND'.
 */
bool
player::gate_state(enum state s1,...)
{
	va_list		ap;
	int		i;
	enum error	err = E_OK;
	bool		in_state = false;

	va_start(ap, s1);
	for (i = (int)s1; !in_state && i != (int)GEND; i = va_arg(ap, int)) {
		if ((int)this->cstate == i) {
			in_state = true;
		}
	}
	va_end(ap);

	return in_state;
}

/* Sets the player state and honks accordingly. */
void
player::set_state(enum state state)
{
	enum state pstate = this->cstate;

	this->cstate = state;

	response(R_STAT, "%s %s", STATES[pstate], STATES[state]);
}
<|endoftext|>


<commit_before>#include "Renderer.h"
#include <exception>

Renderer::Renderer(int width, int height, int flags)
{
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
		throw new std::exception("Failed to initalize SDL");

	win = SDL_CreateWindow("Snake++", 100, 100, width, height, flags);
	if (win == nullptr)
		throw new std::exception("Failed to create window");

	renderer = SDL_CreateRenderer(win, -1, NULL);
	if (renderer == nullptr)
		throw new std::exception("Failed to create SDL renderer");

	surface = SDL_CreateRGBSurface(0, 800, 600, 32, 0, 0, 0, 0);
	if (surface == nullptr)
		throw new std::exception("Failed to create surface");
}

void Renderer::Render()
{
	while (!quit)
	{
		SDL_Event e;
		while (SDL_PollEvent(&e))
			GetGameObject().ProcessEvent(e);

		GetGameObject().Draw();

		SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, surface);

		SDL_RenderClear(renderer);
		SDL_RenderCopy(renderer, tex, NULL, NULL);
		SDL_RenderPresent(renderer);

		SDL_DestroyTexture(tex);
	}
}

void Renderer::Quit()
{
	quit = true;
}

SDL_Surface & Renderer::GetSurface()
{
	return *surface;
}

Renderer::~Renderer()
{
	if (win != nullptr)
		SDL_DestroyWindow(win);

	if (renderer != nullptr)
		SDL_DestroyRenderer(renderer);

	SDL_Quit();
}<commit_msg>Removed hardcoded values from Renderer class<commit_after>#include "Renderer.h"
#include <exception>

Renderer::Renderer(int width, int height, int flags)
{
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
		throw new std::exception("Failed to initalize SDL");

	win = SDL_CreateWindow("Snake++", 100, 100, width, height, flags);
	if (win == nullptr)
		throw new std::exception("Failed to create window");

	renderer = SDL_CreateRenderer(win, -1, NULL);
	if (renderer == nullptr)
		throw new std::exception("Failed to create SDL renderer");

	surface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
	if (surface == nullptr)
		throw new std::exception("Failed to create surface");
}

void Renderer::Render()
{
	while (!quit)
	{
		SDL_Event e;
		while (SDL_PollEvent(&e))
			GetGameObject().ProcessEvent(e);

		GetGameObject().Draw();

		SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, surface);

		SDL_RenderClear(renderer);
		SDL_RenderCopy(renderer, tex, NULL, NULL);
		SDL_RenderPresent(renderer);

		SDL_DestroyTexture(tex);
	}
}

void Renderer::Quit()
{
	quit = true;
}

SDL_Surface & Renderer::GetSurface()
{
	return *surface;
}

Renderer::~Renderer()
{
	if (win != nullptr)
		SDL_DestroyWindow(win);

	if (renderer != nullptr)
		SDL_DestroyRenderer(renderer);

	SDL_Quit();
}<|endoftext|>


<commit_before>#include <iostream>
#include "FontManager.hh"

#include <cereal/archives/xml.hpp>
#include <Core/Renderer.hh>
#include <Context/IRenderContext.hh>
#include <glm/gtc/matrix_transform.hpp>

FontManager::FontManager(std::weak_ptr<Engine> engine)
: Dependency()
, PubSub(engine.lock()->getInstance<PubSub::Manager>())
{}

FontManager::~FontManager()
{}

bool FontManager::init()
{
	globalSub(std::string("endOfFrame"), [&](){
		_drawList();
	});

	std::array<Attribute, 2> param =
	{
		Attribute(GL_FLOAT, sizeof(float), 4), //-V112
		Attribute(GL_FLOAT, sizeof(float), 2),
	};
	_vertexManager = std::make_unique<VertexManager<2>>(param);
	return _vertexManager->init();
}

bool FontManager::loadFont(const File &file, const std::string &name)
{
	if (!name.empty())
	{
		if (_collection.find(name) != std::end(_collection))
			return true;
	}

	if (!file.exists())
	{
		std::cerr << "Font file " << file.getFullName() << " not found" << std::endl;
	}

	Font font;

	std::ifstream s(file.getFullName(), std::ios_base::binary);
	if (!s.is_open())
	{
		std::cerr << "File " << file.getFullName() << " is not open." << std::endl;
		return false;
	}

	cereal::PortableBinaryInputArchive ar(s);
	ar(font);
	s.close();

	if (!font.load(_vertexManager))
	{
		std::cerr << "Fail to load font: " << file.getFullName() << std::endl;
		return false;
	}
	_collection.insert(std::make_pair(font._name, font));

	return true;
}

bool FontManager::isLoaded(const std::string &name)
{
	return _collection.find(name) != std::end(_collection);
}

void FontManager::_drawList()
{
	for (auto &e : _toDraw)
	{
		_draw2DString(e.str, e.fontName, e.size, e.position, e.color, e.shader);
	}
	_toDraw.clear();
}

void FontManager::_draw2DString(const std::string &text,
	const std::string &fontName,
	std::size_t size,
	const glm::ivec2 &position,
	const glm::vec4 &color,
	const std::string &shader)
{
	auto s = _dpyManager.lock()->getInstance<Renderer>()->getShader(shader);
	if (!s)
		return;
	s->use();

	auto font = _collection.find(fontName);
	if (font == std::end(_collection) || !font->second.isLoaded())
	{
		std::cerr << "Font not found : " << fontName << std::endl;
		return;
	}

	auto fontSize = font->second._sizes.find(size);
	if (fontSize == std::end(font->second._sizes))
	{
		fontSize = font->second._sizes.upper_bound(size);
		if (fontSize == std::end(font->second._sizes))
		{
			fontSize = --font->second._sizes.end();
		}
	}
	if (!fontSize->second.isLoaded())
	{
		std::cerr << "Size [" << size << "] for font " << fontName << " is not loaded." << std::endl;
		return;
	}
	auto &f = fontSize->second;
	float sz = static_cast<float>(f._size);
	if (sz != static_cast<float>(size))
		sz = static_cast<float>(size);
	glm::mat4 transformation(1);
	transformation = glm::translate(transformation, glm::vec3(position.x, position.y, 0));

	glUniform1i(glGetUniformLocation(s->getId(), "fTexture0"), 0);
	glUniform4f(glGetUniformLocation(s->getId(), "color"), color.x, color.y, color.z, color.a);
	glm::ivec2 screen = _dpyManager.lock()->getInstance<IRenderContext>()->getScreenSize();
	glm::mat4 Projection = glm::mat4(1);
	Projection *= glm::ortho(0.0f, (float)screen.x, (float)screen.y, 0.0f, -1.0f, 1.0f);
	glUniformMatrix4fv(glGetUniformLocation(s->getId(), "projection"), 1, GL_FALSE, glm::value_ptr(Projection));
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, f._textureId);
	auto transformationID = glGetUniformLocation(s->getId(), "transformation");
	auto glyphWidth = 0.0f;
	float lastX = static_cast<float>(position.x);
	float lineWidth = 0.0f;
	for (std::size_t i = 0; i < text.size(); ++i)
	{
		std::size_t l = std::size_t(text[i] - ASCII_BEGIN);
		glyphWidth = f._size != size ? ((float)f._map[l].width / (float)f._size) * sz : f._map[l].width;
		if (text[i] == ' ')
		{
			lastX = sz / 3.0f;
		}
		else if (text[i] == '\n')
		{
			transformation = glm::translate(transformation, glm::vec3(-lineWidth, f._glyphSize, 0));
			lineWidth = 0;
			continue;
		}
		else
		{
			lastX = glyphWidth;
		}
		lineWidth += lastX;
		glUniformMatrix4fv(transformationID, 1, GL_FALSE, glm::value_ptr(transformation));
		f._map[l].buffer->draw(GL_QUADS);
		transformation = glm::translate(transformation, glm::vec3(lastX, 0, 0));
	}
}

void FontManager::draw2DString(const std::string &text,
	const std::string &fontName,
	std::size_t size,
	const glm::ivec2 &position,
	const glm::vec4 &color,
	const std::string &shader)
{
	_toDraw.emplace_back(text, fontName, size, position, color, shader);
}<commit_msg>Font manager draw 2d text secured<commit_after>#include <iostream>
#include "FontManager.hh"

#include <cereal/archives/xml.hpp>
#include <Core/Renderer.hh>
#include <Context/IRenderContext.hh>
#include <glm/gtc/matrix_transform.hpp>

FontManager::FontManager(std::weak_ptr<Engine> engine)
: Dependency()
, PubSub(engine.lock()->getInstance<PubSub::Manager>())
{}

FontManager::~FontManager()
{}

bool FontManager::init()
{
	globalSub(std::string("endOfFrame"), [&](){
		_drawList();
	});

	std::array<Attribute, 2> param =
	{
		Attribute(GL_FLOAT, sizeof(float), 4), //-V112
		Attribute(GL_FLOAT, sizeof(float), 2),
	};
	_vertexManager = std::make_unique<VertexManager<2>>(param);
	return _vertexManager->init();
}

bool FontManager::loadFont(const File &file, const std::string &name)
{
	if (!name.empty())
	{
		if (_collection.find(name) != std::end(_collection))
			return true;
	}

	if (!file.exists())
	{
		std::cerr << "Font file " << file.getFullName() << " not found" << std::endl;
	}

	Font font;

	std::ifstream s(file.getFullName(), std::ios_base::binary);
	if (!s.is_open())
	{
		std::cerr << "File " << file.getFullName() << " is not open." << std::endl;
		return false;
	}

	cereal::PortableBinaryInputArchive ar(s);
	ar(font);
	s.close();

	if (!font.load(_vertexManager))
	{
		std::cerr << "Fail to load font: " << file.getFullName() << std::endl;
		return false;
	}
	_collection.insert(std::make_pair(font._name, font));

	return true;
}

bool FontManager::isLoaded(const std::string &name)
{
	return _collection.find(name) != std::end(_collection);
}

void FontManager::_drawList()
{
	for (auto &e : _toDraw)
	{
		_draw2DString(e.str, e.fontName, e.size, e.position, e.color, e.shader);
	}
	_toDraw.clear();
}

void FontManager::_draw2DString(const std::string &text,
	const std::string &fontName,
	std::size_t size,
	const glm::ivec2 &position,
	const glm::vec4 &color,
	const std::string &shader)
{
	auto s = _dpyManager.lock()->getInstance<Renderer>()->getShader(shader);
	if (!s)
		return;
	s->use();

	auto font = _collection.find(fontName);
	if (font == std::end(_collection) || !font->second.isLoaded())
	{
		std::cerr << "Font not found : " << fontName << std::endl;
		return;
	}

	auto fontSize = font->second._sizes.find(size);
	if (fontSize == std::end(font->second._sizes))
	{
		fontSize = font->second._sizes.upper_bound(size);
		if (fontSize == std::end(font->second._sizes))
		{
			fontSize = --font->second._sizes.end();
		}
	}
	if (!fontSize->second.isLoaded())
	{
		std::cerr << "Size [" << size << "] for font " << fontName << " is not loaded." << std::endl;
		return;
	}
	auto &f = fontSize->second;
	float sz = static_cast<float>(f._size);
	if (sz != static_cast<float>(size))
		sz = static_cast<float>(size);
	glm::mat4 transformation(1);
	transformation = glm::translate(transformation, glm::vec3(position.x, position.y, 0));

	glUniform1i(glGetUniformLocation(s->getId(), "fTexture0"), 0);
	glUniform4f(glGetUniformLocation(s->getId(), "color"), color.x, color.y, color.z, color.a);
	glm::ivec2 screen = _dpyManager.lock()->getInstance<IRenderContext>()->getScreenSize();
	glm::mat4 Projection = glm::mat4(1);
	Projection *= glm::ortho(0.0f, (float)screen.x, (float)screen.y, 0.0f, -1.0f, 1.0f);
	glUniformMatrix4fv(glGetUniformLocation(s->getId(), "projection"), 1, GL_FALSE, glm::value_ptr(Projection));
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, f._textureId);
	auto transformationID = glGetUniformLocation(s->getId(), "transformation");
	auto glyphWidth = 0.0f;
	float lastX = static_cast<float>(position.x);
	float lineWidth = 0.0f;
	for (std::size_t i = 0; i < text.size(); ++i)
	{
		std::size_t l = std::size_t(text[i] - ASCII_BEGIN);
		if (l > ASCII_END)
			glyphWidth = size;
		else
			glyphWidth = f._size != size ? ((float)f._map[l].width / (float)f._size) * sz : f._map[l].width;
		if (text[i] == ' ')
		{
			lastX = sz / 3.0f;
		}
		else if (text[i] == '\n')
		{
			transformation = glm::translate(transformation, glm::vec3(-lineWidth, f._glyphSize, 0));
			lineWidth = 0;
			continue;
		}
		else
		{
			lastX = glyphWidth;
		}
		lineWidth += lastX;
		glUniformMatrix4fv(transformationID, 1, GL_FALSE, glm::value_ptr(transformation));
		f._map[l].buffer->draw(GL_QUADS);
		transformation = glm::translate(transformation, glm::vec3(lastX, 0, 0));
	}
}

void FontManager::draw2DString(const std::string &text,
	const std::string &fontName,
	std::size_t size,
	const glm::ivec2 &position,
	const glm::vec4 &color,
	const std::string &shader)
{
	_toDraw.emplace_back(text, fontName, size, position, color, shader);
}<|endoftext|>


<commit_before>#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <string>
#include <sys/time.h>
#include <thread>

#include <rclcpp/rclcpp.hpp>

#include <simple_msgs/AllBuiltinTypes.h>
#include <simple_msgs/AllDynamicArrayTypes.h>
#include <simple_msgs/AllPrimitiveTypes.h>
#include <simple_msgs/AllStaticArrayTypes.h>
#include <simple_msgs/Nested.h>
#include <simple_msgs/String.h>
#include <simple_msgs/Uint32.h>

#include <userland_msgs/AddTwoInts.h>

int main(int argc, char** argv)
{
  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("add_two_ints_client");

  auto client = node->create_client<userland_msgs::AddTwoInts>("add_two_ints");
  auto request = std::make_shared<userland_msgs::AddTwoInts::Request>();
  auto response = std::make_shared<userland_msgs::AddTwoInts::Response>();
  request->a = 2;
  request->b = 3;

  auto f = client->async_send_request(request, response);

  std::future_status status;
  do
  {
    rclcpp::spin_some(node);
    status = f.wait_for(std::chrono::milliseconds(100));
  } while(status != std::future_status::ready && rclcpp::ok());

  if(std::future_status::ready == status)
  {
    std::cout << "FUTURE READY" << std::endl;
    std::cout << f.get()->sum << std::endl;
  }

  client->async_send_request(
    request, response,
    [] (rclcpp::client::Client<userland_msgs::AddTwoInts>::SharedFuture f) {
      std::cout << "CALLBACK" << std::endl;
  });
  rclcpp::spin(node);

  return 0;
}
<commit_msg>Remove response parameter. Added callback-based example<commit_after>#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <string>
#include <sys/time.h>
#include <thread>

#include <rclcpp/rclcpp.hpp>

#include <simple_msgs/AllBuiltinTypes.h>
#include <simple_msgs/AllDynamicArrayTypes.h>
#include <simple_msgs/AllPrimitiveTypes.h>
#include <simple_msgs/AllStaticArrayTypes.h>
#include <simple_msgs/Nested.h>
#include <simple_msgs/String.h>
#include <simple_msgs/Uint32.h>

#include <userland_msgs/AddTwoInts.h>

int main(int argc, char** argv)
{
  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("add_two_ints_client");

  auto client = node->create_client<userland_msgs::AddTwoInts>("add_two_ints");
  auto request = std::make_shared<userland_msgs::AddTwoInts::Request>();
  request->a = 2;
  request->b = 3;

  auto f = client->async_send_request(request);

  std::future_status status;
  do
  {
    rclcpp::spin_some(node);
    status = f.wait_for(std::chrono::milliseconds(100));
  } while(status != std::future_status::ready && rclcpp::ok());

  if(std::future_status::ready == status)
  {
    std::cout << "FUTURE READY" << std::endl;
    std::cout << f.get()->sum << std::endl;
  }

  client->async_send_request(
    request,
    [] (rclcpp::client::Client<userland_msgs::AddTwoInts>::SharedFuture cb_f) {
      std::cout << "CALLBACK" << std::endl;
      std::cout << cb_f.get()->sum << std::endl;
  });
  rclcpp::spin(node);

  return 0;
}
<|endoftext|>


<commit_before>/*=================================================================================================
  Glance World Editor - (C) 2013 Daniel L. Watkins

  Filename: WorldEditor.cpp
  Created: 4/20/2013 @ 20:42 UTC-6
=================================================================================================*/
#include "Main.h"

namespace ge
{
	namespace gwe
	{
		void WorldEditor::_CreateUserInterface()
		{
			using namespace gui;

			if (!mRoot)
				gDebug.Error(String()+"Bad root object. Cannot create user interface for WorldEditor instance "+ToString(this));

			//create the main menu bar
			WeakPtr<MenuBar> menuBar = mRoot->CreateMenuBar(gwe::EID_MENU_BAR_MAIN, -1, Vector2D<int>(), mRoot->GetWindow()->GetWidth());
				mFileMenu = menuBar.lock()->AddMenu("File");
					 mFileMenu.lock()->AddItem("Open");
					mFileMenu.lock()->AddItem("Exit");
				WeakPtr<ContextMenu> cm2 = menuBar.lock()->AddMenu("Help");
					cm2.lock()->AddItem("About");
		}

		void WorldEditor::_CreateOpenDialog()
		{
			int width = 300;
			int height = 600;
			Vector2D<int> centeredPosition(mRoot->GetWindow()->GetWidth()/2-width/2, mRoot->GetWindow()->GetHeight()/2-height/2);
			mOpenDialog = mRoot->CreateDialogBox(EID_OPEN_DIALOG, -1, centeredPosition, width, height, "Open World");
				WeakPtr<ListBox> worldListBox = mRoot->CreateListBox(EID_OPEN_WORLD_LISTBOX, mOpenDialog, Vector2D<int>(10,40), 200, 150);
				mRoot->CreateButtonCaption(EID_OPEN_WORLD_BUTTON, mOpenDialog, Vector2D<int>(220,40), 70, 24, "Open");
				mOpenDialog.lock()->AddElementListener(this);

			io::DirectoryListing worldListing = io::GetFilesInDirectory(DIR_WORLDS, ".world");
			io::DirectoryListing::iterator iter = worldListing.begin();
			while (iter != worldListing.end())
			{
				String shortendPath = io::Standardize(*iter);
				shortendPath.RemoveUntil("/",128,true);
				worldListBox.lock()->AddCell(shortendPath, *iter);

				iter++;
			}

			//Element testing
			WeakPtr<ButtonCaption> bc = mRoot->CreateButtonCaption(12345600, mOpenDialog, Vector2D<int>(10,220), 120, 24, "FUCK YOU");
			bc.lock()->AddElementListener(this);

			WeakPtr<CheckBox> cb = mRoot->CreateCheckBox(12345601, mOpenDialog, Vector2D<int>(10,250), "Fuck YOU");
			cb.lock()->AddElementListener(this);

			WeakPtr<EditBox> eb = mRoot->CreateEditBox(12345610, mOpenDialog, Vector2D<int>(140,220), 120, 24, "");
			eb.lock()->AddElementListener(this);

			WeakPtr<Slider> sl = mRoot->CreateSlider(12345611, mOpenDialog, Vector2D<int>(140,250), 120);
			sl.lock()->AddElementListener(this);

			WeakPtr<ComboBox> combo = mRoot->CreateComboBox(13245612, mOpenDialog, Vector2D<int>(10,390), 150);
			combo.lock()->AddCell("Low", "Low");
			combo.lock()->AddCell("Medium", "Medium");
			combo.lock()->AddCell("High", "High");
			combo.lock()->AddCell("Ultra", "Ultra");
			combo.lock()->AddElementListener(this);

			WeakPtr<ListBox> lbox = mRoot->CreateListBox(12345613, mOpenDialog, Vector2D<int>(170,390), 150, 200);
			lbox.lock()->AddCell("Low", "Low");
			lbox.lock()->AddCell("Medium", "Medium");
			lbox.lock()->AddCell("High", "High");
			lbox.lock()->AddCell("Ultra", "Ultra");
			lbox.lock()->AddElementListener(this);
		}

		void WorldEditor::Init()
		{
			_CreateUserInterface();
		}

		void WorldEditor::Update()
		{
			if (mWorld)
				mWorld->Update(1.0);

			_UpdateScrolling();

			if (mFileMenu.lock()->GetSelectedCaption() == "Open"  &&  mOpenDialog.expired())
				_CreateOpenDialog();

			/*if (mOpenDialog.expired() == false)
			{
				WeakPtr<ButtonCaption> openWorld = DynamicPtrCast<ButtonCaption>(mOpenDialog.lock()->GetChild(EID_OPEN_WORLD_BUTTON).lock());
				if (!openWorld.expired()  &&  openWorld.lock()->GetState() == State::RELEASED)
				{
					WeakPtr<ListBox> worldListBox = DynamicPtrCast<ListBox>(mOpenDialog.lock()->GetChild(EID_OPEN_WORLD_LISTBOX).lock());
					String worldPath = worldListBox.lock()->GetSelectedCell().lock()->GetUID();
					LoadWorld(worldPath);
					mOpenDialog.lock()->ScheduleToBeRemoved();
				}
			}*/

			mFileMenu.lock()->ClearSelectedCaption();

			if (mCamera)
				mCamera->Draw();
		}

		void WorldEditor::SendElementMessage(ElementEvent elementEvent, WeakPtr<Element> element, String eventParam)
		{
			std::cout << "ElemenetEvent [" << (int)elementEvent << "] for element instance at 0x" << element.lock().get() << " with event parameter " << eventParam.GetStd() << std::endl;
		}

		void WorldEditor::LoadWorld(String worldPath)
		{
			mWorld = SharedPtr<world::World>(new world::World);
			mWorld->Init();
			mWorld->LoadWorldFromFile(worldPath);

			mCamera = SharedPtr<world::Camera>(new world::Camera);
			mCamera->SetWindow(mRoot->GetWindow());
			mCamera->SetWorld(mWorld.get());  //TODO the camera should store a WeakPtr to the world, not raw
			mCamera->SetViewSize(mRoot->GetWindow()->GetWidth(), mRoot->GetWindow()->GetHeight()-30);
			mCamera->SetScreenPos(0,30);

			mEntityListBox = mRoot->CreateListBox(1253, -1, Vector2D<int>(0,24), 160, mRoot->GetWindow()->GetHeight()-24);

			for (int n=0; n<mWorld->GetEntityManager()->TemplateEntityCount(); n++)
			{
				WeakPtr<world::Entity> templateEntity = mWorld->GetEntityManager()->GetTemplateEntity(n);
				mEntityListBox.lock()->AddCell(templateEntity.lock()->GetDisplayName(), templateEntity.lock()->GetName());
			}
		}

		void WorldEditor::_UpdateScrolling()
		{
			if (!mCamera)
				return;

			double SP = 7.5;
			#define DIAG 0.7071067811865475*SP

			bool up = mRoot->GetWindow()->GetInput()->GetKeyState(GK_W, KEY_DOWN);
			bool down = mRoot->GetWindow()->GetInput()->GetKeyState(GK_S, KEY_DOWN);
			bool left = mRoot->GetWindow()->GetInput()->GetKeyState(GK_A, KEY_DOWN);
			bool right = mRoot->GetWindow()->GetInput()->GetKeyState(GK_D, KEY_DOWN);

			//west
			if (!up && !down && left && !right)
				mCamera->Move(-SP, 0.0, 0.0);
			//north west
			if (up && !down && left && !right)
				mCamera->Move(-DIAG, -DIAG, 0.0);
			//north
			else if (up && !down && !left && !right)
					mCamera->Move(0.0, -SP, 0.0);
			//north east
			else if (up && !down && !left && right)
				mCamera->Move(DIAG, -DIAG, 0.0);
			//east
			else if (!up && !down && !left && right)
				mCamera->Move(SP, 0.0, 0.0);
			//south east
			else if (!up && down && !left && right)
				mCamera->Move(DIAG, DIAG, 0.0);
				//south
			else if (!up && down && !left && !right)
				mCamera->Move(0.0, SP, 0.0);
			//south west
			else if (!up && down && left && !right)
				mCamera->Move(-DIAG, DIAG, 0.0);
		}
	};
};<commit_msg>Cleaned up the WorldEditor class<commit_after>/*=================================================================================================
  Glance World Editor - (C) 2013 Daniel L. Watkins

  Filename: WorldEditor.cpp
  Created: 4/20/2013 @ 20:42 UTC-6
=================================================================================================*/
#include "Main.h"

namespace ge
{
	namespace gwe
	{
		/*=============================================================================
		-- Generates the default user interface at start up.
		=============================================================================*/
		void WorldEditor::_CreateUserInterface()
		{
			using namespace gui;

			if (!mRoot)
				gDebug.Error(String()+"Bad root object. Cannot create user interface for WorldEditor instance "+ToString(this));

			//create the main menu bar
			WeakPtr<MenuBar> menuBar = mRoot->CreateMenuBar(gwe::EID_MENU_BAR_MAIN, -1, Vector2D<int>(), mRoot->GetWindow()->GetWidth());
				mFileMenu = menuBar.lock()->AddMenu("File");
					 mFileMenu.lock()->AddItem("Open");
					mFileMenu.lock()->AddItem("Exit");
				WeakPtr<ContextMenu> cm2 = menuBar.lock()->AddMenu("Help");
					cm2.lock()->AddItem("About");
		}

		/*=============================================================================
		-- Creates the open world dialog.
		=============================================================================*/
		void WorldEditor::_CreateOpenDialog()
		{
			int width = 300;
			int height = 600;
			Vector2D<int> centeredPosition(mRoot->GetWindow()->GetWidth()/2-width/2, mRoot->GetWindow()->GetHeight()/2-height/2);
			mOpenDialog = mRoot->CreateDialogBox(EID_OPEN_DIALOG, -1, centeredPosition, width, height, "Open World");
				WeakPtr<ListBox> worldListBox = mRoot->CreateListBox(EID_OPEN_WORLD_LISTBOX, mOpenDialog, Vector2D<int>(10,40), 200, 150);
				WeakPtr<ButtonCaption> openButton = mRoot->CreateButtonCaption(EID_OPEN_WORLD_BUTTON, mOpenDialog, Vector2D<int>(220,40), 70, 24, "Open");
				openButton.lock()->AddElementListener(this);

			io::DirectoryListing worldListing = io::GetFilesInDirectory(DIR_WORLDS, ".world");
			io::DirectoryListing::iterator iter = worldListing.begin();
			while (iter != worldListing.end())
			{
				String shortendPath = io::Standardize(*iter);
				shortendPath.RemoveUntil("/",128,true);
				worldListBox.lock()->AddCell(shortendPath, *iter);

				iter++;
			}
		}

		/*=============================================================================
		-- Init
		=============================================================================*/
		void WorldEditor::Init()
		{
			_CreateUserInterface();
		}

		/*=============================================================================
		-- Update
		=============================================================================*/
		void WorldEditor::Update()
		{
			if (mWorld)
				mWorld->Update(1.0);

			_UpdateScrolling();

			if (mFileMenu.lock()->GetSelectedCaption() == "Open"  &&  mOpenDialog.expired())
				_CreateOpenDialog();

			/*if (mOpenDialog.expired() == false)
			{
				WeakPtr<ButtonCaption> openWorld = DynamicPtrCast<ButtonCaption>(mOpenDialog.lock()->GetChild(EID_OPEN_WORLD_BUTTON).lock());
				if (!openWorld.expired()  &&  openWorld.lock()->GetState() == State::RELEASED)
				{
					WeakPtr<ListBox> worldListBox = DynamicPtrCast<ListBox>(mOpenDialog.lock()->GetChild(EID_OPEN_WORLD_LISTBOX).lock());
					String worldPath = worldListBox.lock()->GetSelectedCell().lock()->GetUID();
					LoadWorld(worldPath);
					mOpenDialog.lock()->ScheduleToBeRemoved();
				}
			}*/

			mFileMenu.lock()->ClearSelectedCaption();

			if (mCamera)
				mCamera->Draw();
		}

		/*=============================================================================
		-- Callback method for responding to gui::Element messages.
		=============================================================================*/
		void WorldEditor::SendElementMessage(ElementEvent elementEvent, WeakPtr<Element> element, String eventParam)
		{
			std::cout << "ElemenetEvent [" << (int)elementEvent << "] for element instance at 0x" << element.lock().get() << " with event parameter " << eventParam.GetStd() << std::endl;
			int elementId = element.lock()->GetId();

			switch (elementId)
			{
				case EID_OPEN_WORLD_BUTTON:
				{
					if (elementEvent == ElementEvent::RELEASED)
					{
						WeakPtr<ListBox> worldListBox = DynamicPtrCast<ListBox>(mOpenDialog.lock()->GetChild(EID_OPEN_WORLD_LISTBOX).lock());
						String worldPath = worldListBox.lock()->GetSelectedCell().lock()->GetUID();
						LoadWorld(worldPath);
						mOpenDialog.lock()->ScheduleToBeRemoved();
					}
				}
			}
		}

		/*=============================================================================
		-- Loads the specified world and sets the camera to view it.
		=============================================================================*/
		void WorldEditor::LoadWorld(String worldPath)
		{
			mWorld = SharedPtr<world::World>(new world::World);
			mWorld->Init();
			mWorld->LoadWorldFromFile(worldPath);

			mCamera = SharedPtr<world::Camera>(new world::Camera);
			mCamera->SetWindow(mRoot->GetWindow());
			mCamera->SetWorld(mWorld.get());  //TODO the camera should store a WeakPtr to the world, not raw
			mCamera->SetViewSize(mRoot->GetWindow()->GetWidth(), mRoot->GetWindow()->GetHeight()-30);
			mCamera->SetScreenPos(0,30);

			mEntityListBox = mRoot->CreateListBox(1253, -1, Vector2D<int>(0,24), 160, mRoot->GetWindow()->GetHeight()-24);

			for (int n=0; n<mWorld->GetEntityManager()->TemplateEntityCount(); n++)
			{
				WeakPtr<world::Entity> templateEntity = mWorld->GetEntityManager()->GetTemplateEntity(n);
				mEntityListBox.lock()->AddCell(templateEntity.lock()->GetDisplayName(), templateEntity.lock()->GetName());
			}
		}

		/*=============================================================================
		-- Updates scrolling based on WASD
		=============================================================================*/
		void WorldEditor::_UpdateScrolling()
		{
			//TODO implement scrolling by holding right-click and moving
			//TODO implement scrolling by moving the cursor to the edge of the window

			if (!mCamera)
				return;

			double SP = 7.5;
			#define DIAG 0.7071067811865475*SP

			bool up = mRoot->GetWindow()->GetInput()->GetKeyState(GK_W, KEY_DOWN);
			bool down = mRoot->GetWindow()->GetInput()->GetKeyState(GK_S, KEY_DOWN);
			bool left = mRoot->GetWindow()->GetInput()->GetKeyState(GK_A, KEY_DOWN);
			bool right = mRoot->GetWindow()->GetInput()->GetKeyState(GK_D, KEY_DOWN);

			//west
			if (!up && !down && left && !right)
				mCamera->Move(-SP, 0.0, 0.0);
			//north west
			if (up && !down && left && !right)
				mCamera->Move(-DIAG, -DIAG, 0.0);
			//north
			else if (up && !down && !left && !right)
					mCamera->Move(0.0, -SP, 0.0);
			//north east
			else if (up && !down && !left && right)
				mCamera->Move(DIAG, -DIAG, 0.0);
			//east
			else if (!up && !down && !left && right)
				mCamera->Move(SP, 0.0, 0.0);
			//south east
			else if (!up && down && !left && right)
				mCamera->Move(DIAG, DIAG, 0.0);
				//south
			else if (!up && down && !left && !right)
				mCamera->Move(0.0, SP, 0.0);
			//south west
			else if (!up && down && left && !right)
				mCamera->Move(-DIAG, DIAG, 0.0);
		}
	};
};<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <map>
#include <pthread.h>
#include <unistd.h>
#include "mvt.hpp"
#include "plugin.hpp"
#include "projection.hpp"
#include "geometry.hpp"

extern "C" {
#include "jsonpull/jsonpull.h"
}

#include "write_json.hpp"
#include "read_json.hpp"

struct writer_arg {
	int *pipe_orig;
	mvt_layer *layer;
	unsigned z;
	unsigned x;
	unsigned y;
};

void *run_writer(void *a) {
	writer_arg *wa = (writer_arg *) a;

	// XXX worry about SIGPIPE?

	FILE *fp = fdopen(wa->pipe_orig[1], "w");
	if (fp == NULL) {
		perror("fdopen (pipe writer)");
		exit(EXIT_FAILURE);
	}

	layer_to_geojson(fp, *(wa->layer), wa->z, wa->x, wa->y);

	if (fclose(fp) != 0) {
		perror("fclose output to filter");
		exit(EXIT_FAILURE);
	}

	return NULL;
}

mvt_layer parse_layer(int fd, unsigned z, unsigned x, unsigned y) {
	mvt_layer ret;

	FILE *f = fdopen(fd, "r");
	if (f == NULL) {
		perror("fdopen filter output");
		exit(EXIT_FAILURE);
	}
	json_pull *jp = json_begin_file(f);

	while (1) {
		json_object *j = json_read(jp);
		if (j == NULL) {
			if (jp->error != NULL) {
				fprintf(stderr, "Filter output:%d: %s\n", jp->line, jp->error);
				if (jp->root != NULL) {
					json_context(jp->root);
				}
				exit(EXIT_FAILURE);
			}

			json_free(jp->root);
			break;
		}

		json_object *type = json_hash_get(j, "type");
		if (type == NULL || type->type != JSON_STRING) {
			continue;
		}
		if (strcmp(type->string, "Feature") != 0) {
			continue;
		}

		json_object *geometry = json_hash_get(j, "geometry");
		if (geometry == NULL) {
			fprintf(stderr, "Filter output:%d: filtered feature with no geometry\n", jp->line);
			json_context(j);
			json_free(j);
			exit(EXIT_FAILURE);
		}

		json_object *properties = json_hash_get(j, "properties");
		if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
			fprintf(stderr, "Filter output:%d: feature without properties hash\n", jp->line);
			json_context(j);
			json_free(j);
			exit(EXIT_FAILURE);
		}

		json_object *geometry_type = json_hash_get(geometry, "type");
		if (geometry_type == NULL) {
			fprintf(stderr, "Filter output:%d: null geometry (additional not reported)\n", jp->line);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		if (geometry_type->type != JSON_STRING) {
			fprintf(stderr, "Filter output:%d: geometry type is not a string\n", jp->line);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		json_object *coordinates = json_hash_get(geometry, "coordinates");
		if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
			fprintf(stderr, "Filter output:%d: feature without coordinates array\n", jp->line);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		int t;
		for (t = 0; t < GEOM_TYPES; t++) {
			if (strcmp(geometry_type->string, geometry_names[t]) == 0) {
				break;
			}
		}
		if (t >= GEOM_TYPES) {
			fprintf(stderr, "Filter output:%d: Can't handle geometry type %s\n", jp->line, geometry_type->string);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		json_free(j);
	}

	json_end(jp);
	return ret;
}

mvt_layer filter_layer(const char *filter, mvt_layer &layer, unsigned z, unsigned x, unsigned y) {
	// This will create two pipes, a new thread, and a new process.
	//
	// The new process will read from one pipe and write to the other, and execute the filter.
	// The new thread will write the GeoJSON to the pipe that leads to the filter.
	// The original thread will read the GeoJSON from the filter and convert it back into vector tiles.

	int pipe_orig[2], pipe_filtered[2];
	if (pipe(pipe_orig) < 0) {
		perror("pipe (original features)");
		exit(EXIT_FAILURE);
	}
	if (pipe(pipe_filtered) < 0) {
		perror("pipe (filtered features)");
		exit(EXIT_FAILURE);
	}

	pid_t pid = fork();
	if (pid < 0) {
		perror("fork");
		exit(EXIT_FAILURE);
	} else if (pid == 0) {
		// child

		if (dup2(pipe_orig[0], 0) < 0) {
			perror("dup child stdin");
			exit(EXIT_FAILURE);
		}
		if (dup2(pipe_filtered[1], 1) < 0) {
			perror("dup child stdout");
			exit(EXIT_FAILURE);
		}
		if (close(pipe_orig[1]) != 0) {
			perror("close output to filter");
			exit(EXIT_FAILURE);
		}
		if (close(pipe_filtered[0]) != 0) {
			perror("close input from filter");
			exit(EXIT_FAILURE);
		}

		// XXX close other fds?

		// XXX add zyx args
		if (execlp("sh", "sh", "-c", filter, NULL) != 0) {
			perror("exec");
			exit(EXIT_FAILURE);
		}
	} else {
		// parent

		if (close(pipe_orig[0]) != 0) {
			perror("close filter-side reader");
			exit(EXIT_FAILURE);
		}
		if (close(pipe_filtered[1]) != 0) {
			perror("close filter-side writer");
			exit(EXIT_FAILURE);
		}

		writer_arg wa;
		wa.pipe_orig = pipe_orig;
		wa.layer = &layer;
		wa.z = z;
		wa.x = x;
		wa.y = y;

		pthread_t writer;
		if (pthread_create(&writer, NULL, run_writer, &wa) != 0) {
			perror("pthread_create (filter writer)");
			exit(EXIT_FAILURE);
		}

		layer = parse_layer(pipe_filtered[0], z, x, y);

		int stat_loc;
		if (waitpid(pid, &stat_loc, 0) < 0) {
			perror("waitpid for filter\n");
			exit(EXIT_FAILURE);
		}

		if (close(pipe_filtered[0]) != 0) {
			perror("close output from filter");
			exit(EXIT_FAILURE);
		}

		void *ret;
		if (pthread_join(writer, &ret) != 0) {
			perror("pthread_join filter writer");
			exit(EXIT_FAILURE);
		}
	}

	return layer;
}
<commit_msg>Parse JSON coming back in and turn it back into features<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <map>
#include <pthread.h>
#include <unistd.h>
#include "mvt.hpp"
#include "plugin.hpp"
#include "projection.hpp"
#include "geometry.hpp"

extern "C" {
#include "jsonpull/jsonpull.h"
}

#include "write_json.hpp"
#include "read_json.hpp"

struct writer_arg {
	int *pipe_orig;
	mvt_layer *layer;
	unsigned z;
	unsigned x;
	unsigned y;
};

void *run_writer(void *a) {
	writer_arg *wa = (writer_arg *) a;

	// XXX worry about SIGPIPE?

	FILE *fp = fdopen(wa->pipe_orig[1], "w");
	if (fp == NULL) {
		perror("fdopen (pipe writer)");
		exit(EXIT_FAILURE);
	}

	layer_to_geojson(fp, *(wa->layer), wa->z, wa->x, wa->y);

	if (fclose(fp) != 0) {
		perror("fclose output to filter");
		exit(EXIT_FAILURE);
	}

	return NULL;
}

// XXX deduplicate
static std::vector<mvt_geometry> to_feature(drawvec &geom) {
	std::vector<mvt_geometry> out;

	for (size_t i = 0; i < geom.size(); i++) {
		out.push_back(mvt_geometry(geom[i].op, geom[i].x, geom[i].y));
	}

	return out;
}

mvt_layer parse_layer(int fd, unsigned z, unsigned x, unsigned y, mvt_layer const &olayer) {
	mvt_layer ret;
	ret.name = olayer.name;
	ret.version = olayer.version;
	ret.extent = olayer.extent;

	FILE *f = fdopen(fd, "r");
	if (f == NULL) {
		perror("fdopen filter output");
		exit(EXIT_FAILURE);
	}
	json_pull *jp = json_begin_file(f);

	while (1) {
		json_object *j = json_read(jp);
		if (j == NULL) {
			if (jp->error != NULL) {
				fprintf(stderr, "Filter output:%d: %s\n", jp->line, jp->error);
				if (jp->root != NULL) {
					json_context(jp->root);
				}
				exit(EXIT_FAILURE);
			}

			json_free(jp->root);
			break;
		}

		json_object *type = json_hash_get(j, "type");
		if (type == NULL || type->type != JSON_STRING) {
			continue;
		}
		if (strcmp(type->string, "Feature") != 0) {
			continue;
		}

		json_object *geometry = json_hash_get(j, "geometry");
		if (geometry == NULL) {
			fprintf(stderr, "Filter output:%d: filtered feature with no geometry\n", jp->line);
			json_context(j);
			json_free(j);
			exit(EXIT_FAILURE);
		}

		json_object *properties = json_hash_get(j, "properties");
		if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
			fprintf(stderr, "Filter output:%d: feature without properties hash\n", jp->line);
			json_context(j);
			json_free(j);
			exit(EXIT_FAILURE);
		}

		json_object *geometry_type = json_hash_get(geometry, "type");
		if (geometry_type == NULL) {
			fprintf(stderr, "Filter output:%d: null geometry (additional not reported)\n", jp->line);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		if (geometry_type->type != JSON_STRING) {
			fprintf(stderr, "Filter output:%d: geometry type is not a string\n", jp->line);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		json_object *coordinates = json_hash_get(geometry, "coordinates");
		if (coordinates == NULL || coordinates->type != JSON_ARRAY) {
			fprintf(stderr, "Filter output:%d: feature without coordinates array\n", jp->line);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		int t;
		for (t = 0; t < GEOM_TYPES; t++) {
			if (strcmp(geometry_type->string, geometry_names[t]) == 0) {
				break;
			}
		}
		if (t >= GEOM_TYPES) {
			fprintf(stderr, "Filter output:%d: Can't handle geometry type %s\n", jp->line, geometry_type->string);
			json_context(j);
			exit(EXIT_FAILURE);
		}

		drawvec dv;
		parse_geometry(t, coordinates, dv, VT_MOVETO, "Filter output", jp->line, j);
		if (mb_geometry[t] == VT_POLYGON) {
			dv = fix_polygon(dv);
		}

		// Scale and offset geometry from global to tile
		for (size_t i = 0; i < dv.size(); i++) {
			long long scale = 1LL << (32 - z);
			dv[i].x = (dv[i].x - scale * x) * olayer.extent / scale;
			dv[i].y = (dv[i].y - scale * y) * olayer.extent / scale;
		}

		if (mb_geometry[t] == VT_POLYGON) {
			dv = clean_or_clip_poly(dv, 0, 0, 0, false);
			if (dv.size() < 3) {
				dv.clear();
			}
		}
		dv = remove_noop(dv, mb_geometry[t], 0);
		if (mb_geometry[t] == VT_POLYGON) {
			dv = close_poly(dv);
		}

		if (dv.size() > 0) {
			mvt_feature feature;
			feature.type = mb_geometry[t];
			feature.geometry = to_feature(dv);

			json_object *id = json_hash_get(j, "id");
			if (id != NULL) {
				feature.id = atoll(id->string);
				feature.has_id = true;
			}

			for (size_t i = 0; i < properties->length; i++) {
				mvt_value v;

				// XXX reconcile with JSON property parsing
				if (properties->values[i]->type == JSON_STRING) {
					v.type = mvt_string;
					v.string_value = std::string(properties->values[i]->string);
				} else if (properties->values[i]->type == JSON_NUMBER) {
					v.type = mvt_double;
					v.numeric_value.double_value = atof(properties->values[i]->string);
				} else {
					continue;
				}

				ret.tag(feature, std::string(properties->keys[i]->string), v);
			}

			ret.features.push_back(feature);
		}

		json_free(j);
	}

	json_end(jp);
	return ret;
}

mvt_layer filter_layer(const char *filter, mvt_layer &layer, unsigned z, unsigned x, unsigned y) {
	// This will create two pipes, a new thread, and a new process.
	//
	// The new process will read from one pipe and write to the other, and execute the filter.
	// The new thread will write the GeoJSON to the pipe that leads to the filter.
	// The original thread will read the GeoJSON from the filter and convert it back into vector tiles.

	int pipe_orig[2], pipe_filtered[2];
	if (pipe(pipe_orig) < 0) {
		perror("pipe (original features)");
		exit(EXIT_FAILURE);
	}
	if (pipe(pipe_filtered) < 0) {
		perror("pipe (filtered features)");
		exit(EXIT_FAILURE);
	}

	pid_t pid = fork();
	if (pid < 0) {
		perror("fork");
		exit(EXIT_FAILURE);
	} else if (pid == 0) {
		// child

		if (dup2(pipe_orig[0], 0) < 0) {
			perror("dup child stdin");
			exit(EXIT_FAILURE);
		}
		if (dup2(pipe_filtered[1], 1) < 0) {
			perror("dup child stdout");
			exit(EXIT_FAILURE);
		}
		if (close(pipe_orig[1]) != 0) {
			perror("close output to filter");
			exit(EXIT_FAILURE);
		}
		if (close(pipe_filtered[0]) != 0) {
			perror("close input from filter");
			exit(EXIT_FAILURE);
		}

		// XXX close other fds?

		// XXX add zyx args
		if (execlp("sh", "sh", "-c", filter, NULL) != 0) {
			perror("exec");
			exit(EXIT_FAILURE);
		}
	} else {
		// parent

		if (close(pipe_orig[0]) != 0) {
			perror("close filter-side reader");
			exit(EXIT_FAILURE);
		}
		if (close(pipe_filtered[1]) != 0) {
			perror("close filter-side writer");
			exit(EXIT_FAILURE);
		}

		writer_arg wa;
		wa.pipe_orig = pipe_orig;
		wa.layer = &layer;
		wa.z = z;
		wa.x = x;
		wa.y = y;

		pthread_t writer;
		if (pthread_create(&writer, NULL, run_writer, &wa) != 0) {
			perror("pthread_create (filter writer)");
			exit(EXIT_FAILURE);
		}

		layer = parse_layer(pipe_filtered[0], z, x, y, layer);

		int stat_loc;
		if (waitpid(pid, &stat_loc, 0) < 0) {
			perror("waitpid for filter\n");
			exit(EXIT_FAILURE);
		}

		if (close(pipe_filtered[0]) != 0) {
			perror("close output from filter");
			exit(EXIT_FAILURE);
		}

		void *ret;
		if (pthread_join(writer, &ret) != 0) {
			perror("pthread_join filter writer");
			exit(EXIT_FAILURE);
		}
	}

	return layer;
}
<|endoftext|>


<commit_before>/* *
* Copyright (c) 2013 Julio Gutierrez
*
* Permission is hereby granted, free of charge, to any person obtaining a co$
* this software and associated documentation files (the "Software"), to deal$
* the Software without restriction, including without limitation the rights $
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell cop$
* the Software, and to permit persons to whom the Software is furnished to d$
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in$
* 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, F$
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR$
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHE$
* 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 "raspboop/Raspboop.h"

namespace raspboop
{
namespace sensors
{

HCSR501::HCSR501()
{
}

HCSR501* HCSR501::Create(int SIGNAL)
{
}

HCSR501::~HCSR501()
{
}

} /* sensors */
} /* raspboop */

<commit_msg>HCSR501: Create implementation<commit_after>/* *
* Copyright (c) 2013 Julio Gutierrez
*
* Permission is hereby granted, free of charge, to any person obtaining a co$
* this software and associated documentation files (the "Software"), to deal$
* the Software without restriction, including without limitation the rights $
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell cop$
* the Software, and to permit persons to whom the Software is furnished to d$
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in$
* 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, F$
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR$
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHE$
* 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 "raspboop/Raspboop.h"

namespace raspboop
{
namespace sensors
{

HCSR501::HCSR501()
{
}

HCSR501* HCSR501::Create(int SIGNAL)
{
	HCSR501* H = (HCSR501*)malloc(sizeof(HCSR501));

	// Not enough memory. Should notify user
	if(H == NULL)
		return NULL;

	new(H) HCSR501;

	H->SignalPin = SIGNAL;

	H->SetInputPin(SIGNAL);

	return H;
}

HCSR501::~HCSR501()
{
}

} /* sensors */
} /* raspboop */

<|endoftext|>