<commit_before>// StaticCylinderBodyConstraint.cpp
//
// Breannan Smith
// Last updated: 09/16/2015

#include "StaticCylinderBodyConstraint.h"

#include "rigidbody3d/StaticGeometry/StaticCylinder.h"

#include <iostream>

//#include "FrictionUtilities.h"

StaticCylinderBodyConstraint::StaticCylinderBodyConstraint( const unsigned body_index, const Vector3s& collision_point, const StaticCylinder& cyl, const unsigned cylinder_index, const VectorXs& q )
: m_body_index( body_index )
, m_r( collision_point - q.segment<3>( 3 * body_index ) )
, m_cyl( cyl )
//, m_cylinder_index( cylinder_index )
{}

StaticCylinderBodyConstraint::~StaticCylinderBodyConstraint()
{}

scalar StaticCylinderBodyConstraint::evalNdotV( const VectorXs& q, const VectorXs& v ) const
{
  std::cerr << "StaticCylinderBodyConstraint::evalNdotV not implemented." << std::endl;
  std::exit( EXIT_FAILURE );
}

void StaticCylinderBodyConstraint::evalgradg( const VectorXs& q, const int col, SparseMatrixsc& G, const FlowableSystem& fsys ) const
{
  assert( q.size() % 12 == 0 );
  const unsigned nbodies{ unsigned( q.size() ) / 12 };

  const Vector3s n{ computeN( q ) };
  assert( fabs( n.norm() - 1.0 ) <= 1.0e-6 );
  assert( fabs( n.dot( m_cyl.axis() ) ) <= 1.0e-6 );

  // MUST BE ADDED GOING DOWN THE COLUMN. DO NOT TOUCH ANOTHER COLUMN.

  // Effect on center of mass position
  assert( col >= 0 );
  assert( col < G.cols() );
  assert( 3 * m_body_index + 2 < unsigned( G.rows() ) );
  G.insert( 3 * m_body_index + 0, col ) = n.x();
  G.insert( 3 * m_body_index + 1, col ) = n.y();
  G.insert( 3 * m_body_index + 2, col ) = n.z();

  // Effect on orientation
  const Vector3s ntilde{ m_r.cross( n ) };
  assert( 3 * ( nbodies + m_body_index ) + 2 < unsigned( G.rows() ) );
  G.insert( 3 * ( nbodies + m_body_index ) + 0, col ) = ntilde.x();
  G.insert( 3 * ( nbodies + m_body_index ) + 1, col ) = ntilde.y();
  G.insert( 3 * ( nbodies + m_body_index ) + 2, col ) = ntilde.z();
}

//void StaticCylinderSphereConstraint::computeGeneralizedFrictionDisk( const VectorXs& q, const VectorXs& v, const int start_column, const int num_samples, SparseMatrixsc& D, VectorXs& gdotD )
//{
//  assert( start_column >= 0 ); assert( start_column < D.cols() );
//  assert( num_samples > 0 ); assert( start_column+num_samples - 1 < D.cols() );
//  assert( q.size() % 12 == 0 ); assert( q.size() == 2 * v.size() );
//
//  const int nbodies = q.size() / 12;
//
//  const Vector3s n = computeN( q );
//
//  // Compute the displacement from the center of mass to the point of contact
//  assert( fabs( n.norm() - 1.0 ) <= 1.0e-10 ); assert( m_r > 0.0 );
//  const Vector3s r_world = - m_r * n;
//
//  // Compute the relative velocity
//  Vector3s tangent_suggestion = computeRelativeVelocityAtCylinderPoint( q, v );
//  if( tangent_suggestion.cross( n ).squaredNorm() < 1.0e-9 ) tangent_suggestion = FrictionUtilities::orthogonalVector( n );
//  tangent_suggestion *= -1.0;
//
//  // Sample the friction disk
//  std::vector<Vector3s> friction_disk( num_samples );
//  FrictionUtilities::generateOrthogonalVectors( n, friction_disk, tangent_suggestion );
//  assert( num_samples == int( friction_disk.size() ) );
//
//  // For each sample of the friction disk
//  for( int i = 0; i < num_samples; ++i )
//  {
//    const int cur_col = start_column + i;
//    assert( cur_col >= 0 ); assert( cur_col < D.cols() );
//
//    // Effect on center of mass
//    D.insert( 3 * m_i + 0, cur_col ) = friction_disk[i].x();
//    D.insert( 3 * m_i + 1, cur_col ) = friction_disk[i].y();
//    D.insert( 3 * m_i + 2, cur_col ) = friction_disk[i].z();
//
//    // Effect on orientation
//    const Vector3s ntilde = r_world.cross( friction_disk[i] );
//    D.insert( 3 * ( nbodies + m_i ) + 0, cur_col ) = ntilde.x();
//    D.insert( 3 * ( nbodies + m_i ) + 1, cur_col ) = ntilde.y();
//    D.insert( 3 * ( nbodies + m_i ) + 2, cur_col ) = ntilde.z();
//
//    // Relative velocity contribution from kinematic scripting
//    assert( cur_col < gdotD.size() );
//    gdotD( cur_col ) = - friction_disk[i].dot( computeCylinderCollisionPointVelocity( q ) );
//  }
//}
//
//void StaticCylinderSphereConstraint::computeSmoothGeneralizedFrictionDisk( const VectorXs& q, const VectorXs& v, const int start_column, SparseMatrixsc& D, VectorXs& gdotD )
//{
//  assert( start_column >= 0 ); assert( start_column < D.cols() ); assert( start_column + 1 < D.cols() );
//  assert( q.size() % 12 == 0 ); assert( q.size() == 2 * v.size() );
//
//  const Vector3s n = computeN( q );
//  assert( fabs( n.norm() - 1.0 ) <= 1.0e-10 );
//
//  std::vector<Vector3s> friction_disk( 2 );
//
//  // Compute the relative velocity to use as a direction for the tangent sample
//  friction_disk[0] = computeRelativeVelocityAtCylinderPoint( q, v );
//  // If the relative velocity is zero, any vector will do
//  if( friction_disk[0].cross( n ).squaredNorm() < 1.0e-9 )
//  {
//    friction_disk[0] = FrictionUtilities::orthogonalVector( n );
//  }
//  // Otherwise project out the component along the normal and normalize the relative velocity
//  else
//  {
//    friction_disk[0] = friction_disk[0] - friction_disk[0].dot( n ) * n;
//    friction_disk[0].normalize();
//  }
//  // Invert the tangent vector in order to oppose
//  friction_disk[0] *= -1.0;
//  assert( fabs( friction_disk[0].norm() - 1.0 ) < 1.0e-6 );
//  assert( fabs( friction_disk[0].dot( n ) ) < 1.0e-6 );
//
//  // Create a second orthogonal sample in the tangent plane
//  friction_disk[1] = friction_disk[0].cross( n ).normalized(); // Don't need to normalize but it won't hurt
//  assert( fabs( friction_disk[1].norm() - 1.0 ) < 1.0e-6 );
//
//  // Compute the displacement from the center of mass to the point of contact
//  assert( m_r > 0.0 );
//  const Vector3s r_world = - m_r * n;
//
//  // For each sample of the friction disk
//  const int nbodies = q.size() / 12;
//  for( int i = 0; i < 2; ++i )
//  {
//    const int cur_col = start_column + i;
//    assert( cur_col >= 0 ); assert( cur_col < D.cols() );
//
//    // Effect on center of mass
//    D.insert( 3 * m_i + 0, cur_col ) = friction_disk[i].x();
//    D.insert( 3 * m_i + 1, cur_col ) = friction_disk[i].y();
//    D.insert( 3 * m_i + 2, cur_col ) = friction_disk[i].z();
//
//    // Effect on orientation
//    const Vector3s ntilde = r_world.cross( friction_disk[i] );
//    D.insert( 3 * ( nbodies + m_i ) + 0, cur_col ) = ntilde.x();
//    D.insert( 3 * ( nbodies + m_i ) + 1, cur_col ) = ntilde.y();
//    D.insert( 3 * ( nbodies + m_i ) + 2, cur_col ) = ntilde.z();
//
//    // Relative velocity contribution from kinematic scripting
//    assert( cur_col < gdotD.size() );
//    gdotD( cur_col ) = - friction_disk[i].dot( computeCylinderCollisionPointVelocity( q ) );
//  }
//}
//
int StaticCylinderBodyConstraint::impactStencilSize() const
{
  return 6;
}

int StaticCylinderBodyConstraint::frictionStencilSize() const
{
  return 6;
}

//void StaticCylinderSphereConstraint::getSimulatedBodyIndices( std::pair<int,int>& bodies ) const
//{
//  bodies.first = m_i;
//  bodies.second = -1;
//}
//
//void StaticCylinderSphereConstraint::computeFrictionMask( const int nbodies, VectorXs& friction_mask ) const
//{
//  std::cerr << "StaticCylinderSphereConstraint::computeFrictionMask not implemented." << std::endl;
//  std::exit( EXIT_FAILURE );
////  assert( 3 * m_i + 2 < friction_mask.size() );
////  assert( 3 * ( m_i + nbodies ) + 2 < friction_mask.size() );
////
////  friction_mask.segment<3>( 3 * m_i ).setConstant( 1.0 );
////  friction_mask.segment<3>( 3 * ( m_i + nbodies ) ).setConstant( 1.0 );
//}
//
//void StaticCylinderSphereConstraint::getBodyIndices( std::pair<int,int>& bodies ) const
//{
//  this->getSimulatedBodyIndices( bodies );
//}

void StaticCylinderBodyConstraint::evalKinematicNormalRelVel( const VectorXs& q, const int strt_idx, VectorXs& gdotN ) const
{
  assert( strt_idx >= 0 ); assert( strt_idx < gdotN.size() );

  const Vector3s n{ computeN( q ) };
  assert( fabs( n.norm() - 1.0 ) <= 1.0e-6 );
  assert( fabs( n.dot( m_cyl.axis() ) ) <= 1.0e-6 );

  gdotN( strt_idx ) = - n.dot( computeCylinderCollisionPointVelocity( q ) );
}

bool StaticCylinderBodyConstraint::conservesTranslationalMomentum() const
{
  return false;
}

bool StaticCylinderBodyConstraint::conservesAngularMomentumUnderImpact() const
{
  return false;
}

bool StaticCylinderBodyConstraint::conservesAngularMomentumUnderImpactAndFriction() const
{
  return false;
}

std::string StaticCylinderBodyConstraint::name() const
{
  return "static_cylinder_body";
}

Vector3s StaticCylinderBodyConstraint::computeN( const VectorXs& q ) const
{
  const Vector3s x_body{ q.segment<3>( 3 * m_body_index ) };
  const Vector3s axis{ m_cyl.axis() };
  Vector3s n{ - ( x_body - m_cyl.x() - axis.dot( x_body - m_cyl.x() ) * axis ) };
  assert( n.norm() > 0.0 );
  return n / n.norm();
}

Vector3s StaticCylinderBodyConstraint::computeCylinderCollisionPointVelocity( const VectorXs& q ) const
{
  // Vector perpendicular to axis in direction of particle
  const Vector3s n{ -computeN( q ) };
  assert( fabs( n.norm() - 1.0 ) <= 1.0e-6 );
  assert( fabs( n.dot( m_cyl.axis() ) ) <= 1.0e-6 );

  // Closest point on axis to the particle
  const Vector3s p{ q.segment<3>( 3 * m_body_index ) - m_cyl.x() - n.dot( q.segment<3>( 3 * m_body_index ) - m_cyl.x() ) * n };
  assert( ( ( p - m_cyl.x() ).cross( m_cyl.axis() ) ).norm() <= 1.0e-6  );

  // Closest point on cylinder to the particle
  const Vector3s r{ p + m_cyl.r() * n };

  return m_cyl.v() + m_cyl.omega().cross( r );
}

VectorXs StaticCylinderBodyConstraint::computeKinematicRelativeVelocity( const VectorXs& q, const VectorXs& v ) const
{
  std::cerr << "Code up StaticCylinderBodyConstraint::computeKinematicRelativeVelocity" << std::endl;
  std::exit( EXIT_FAILURE );
}

//Vector3s StaticCylinderSphereConstraint::computeRelativeVelocityAtCylinderPoint( const VectorXs& q, const VectorXs& v ) const
//{
//  assert( v.size() % 6 == 0 ); assert( v.size() / 2 + 3 * m_i + 2 < v.size() );
//
//  const int nbodies = v.size() / 6;
//
//  const Vector3s r_sphere = - m_r * computeN( q );
//
//  // v + omega x r
//  return v.segment<3>( 3 * m_i ) + v.segment<3>( 3 * ( nbodies + m_i ) ).cross( r_sphere ) - computeCylinderCollisionPointVelocity( q );
//}

//void StaticCylinderSphereConstraint::getWorldSpaceContactPoint( const VectorXs& q, VectorXs& contact_point )
//{
//  contact_point = q.segment<3>( 3 * m_i ) - m_r * computeN( q );
//}

//void StaticCylinderSphereConstraint::getWorldSpaceContactNormal( const VectorXs& q, VectorXs& contact_normal )
//{
//  contact_normal = computeN( q );
//}

//unsigned StaticCylinderSphereConstraint::getStaticObjectIndex() const
//{
//  return m_cylinder_index;
//}
<commit_msg>Trivial implementation of StaticCylinderBodyConstraint computeKinematicRelativeVelocity method.<commit_after>// StaticCylinderBodyConstraint.cpp
//
// Breannan Smith
// Last updated: 09/22/2015

#include "StaticCylinderBodyConstraint.h"

#include "rigidbody3d/StaticGeometry/StaticCylinder.h"

#include <iostream>

//#include "FrictionUtilities.h"

StaticCylinderBodyConstraint::StaticCylinderBodyConstraint( const unsigned body_index, const Vector3s& collision_point, const StaticCylinder& cyl, const unsigned cylinder_index, const VectorXs& q )
: m_body_index( body_index )
, m_r( collision_point - q.segment<3>( 3 * body_index ) )
, m_cyl( cyl )
//, m_cylinder_index( cylinder_index )
{}

StaticCylinderBodyConstraint::~StaticCylinderBodyConstraint()
{}

scalar StaticCylinderBodyConstraint::evalNdotV( const VectorXs& q, const VectorXs& v ) const
{
  std::cerr << "StaticCylinderBodyConstraint::evalNdotV not implemented." << std::endl;
  std::exit( EXIT_FAILURE );
}

void StaticCylinderBodyConstraint::evalgradg( const VectorXs& q, const int col, SparseMatrixsc& G, const FlowableSystem& fsys ) const
{
  assert( q.size() % 12 == 0 );
  const unsigned nbodies{ unsigned( q.size() ) / 12 };

  const Vector3s n{ computeN( q ) };
  assert( fabs( n.norm() - 1.0 ) <= 1.0e-6 );
  assert( fabs( n.dot( m_cyl.axis() ) ) <= 1.0e-6 );

  // MUST BE ADDED GOING DOWN THE COLUMN. DO NOT TOUCH ANOTHER COLUMN.

  // Effect on center of mass position
  assert( col >= 0 );
  assert( col < G.cols() );
  assert( 3 * m_body_index + 2 < unsigned( G.rows() ) );
  G.insert( 3 * m_body_index + 0, col ) = n.x();
  G.insert( 3 * m_body_index + 1, col ) = n.y();
  G.insert( 3 * m_body_index + 2, col ) = n.z();

  // Effect on orientation
  const Vector3s ntilde{ m_r.cross( n ) };
  assert( 3 * ( nbodies + m_body_index ) + 2 < unsigned( G.rows() ) );
  G.insert( 3 * ( nbodies + m_body_index ) + 0, col ) = ntilde.x();
  G.insert( 3 * ( nbodies + m_body_index ) + 1, col ) = ntilde.y();
  G.insert( 3 * ( nbodies + m_body_index ) + 2, col ) = ntilde.z();
}

//void StaticCylinderSphereConstraint::computeGeneralizedFrictionDisk( const VectorXs& q, const VectorXs& v, const int start_column, const int num_samples, SparseMatrixsc& D, VectorXs& gdotD )
//{
//  assert( start_column >= 0 ); assert( start_column < D.cols() );
//  assert( num_samples > 0 ); assert( start_column+num_samples - 1 < D.cols() );
//  assert( q.size() % 12 == 0 ); assert( q.size() == 2 * v.size() );
//
//  const int nbodies = q.size() / 12;
//
//  const Vector3s n = computeN( q );
//
//  // Compute the displacement from the center of mass to the point of contact
//  assert( fabs( n.norm() - 1.0 ) <= 1.0e-10 ); assert( m_r > 0.0 );
//  const Vector3s r_world = - m_r * n;
//
//  // Compute the relative velocity
//  Vector3s tangent_suggestion = computeRelativeVelocityAtCylinderPoint( q, v );
//  if( tangent_suggestion.cross( n ).squaredNorm() < 1.0e-9 ) tangent_suggestion = FrictionUtilities::orthogonalVector( n );
//  tangent_suggestion *= -1.0;
//
//  // Sample the friction disk
//  std::vector<Vector3s> friction_disk( num_samples );
//  FrictionUtilities::generateOrthogonalVectors( n, friction_disk, tangent_suggestion );
//  assert( num_samples == int( friction_disk.size() ) );
//
//  // For each sample of the friction disk
//  for( int i = 0; i < num_samples; ++i )
//  {
//    const int cur_col = start_column + i;
//    assert( cur_col >= 0 ); assert( cur_col < D.cols() );
//
//    // Effect on center of mass
//    D.insert( 3 * m_i + 0, cur_col ) = friction_disk[i].x();
//    D.insert( 3 * m_i + 1, cur_col ) = friction_disk[i].y();
//    D.insert( 3 * m_i + 2, cur_col ) = friction_disk[i].z();
//
//    // Effect on orientation
//    const Vector3s ntilde = r_world.cross( friction_disk[i] );
//    D.insert( 3 * ( nbodies + m_i ) + 0, cur_col ) = ntilde.x();
//    D.insert( 3 * ( nbodies + m_i ) + 1, cur_col ) = ntilde.y();
//    D.insert( 3 * ( nbodies + m_i ) + 2, cur_col ) = ntilde.z();
//
//    // Relative velocity contribution from kinematic scripting
//    assert( cur_col < gdotD.size() );
//    gdotD( cur_col ) = - friction_disk[i].dot( computeCylinderCollisionPointVelocity( q ) );
//  }
//}
//
//void StaticCylinderSphereConstraint::computeSmoothGeneralizedFrictionDisk( const VectorXs& q, const VectorXs& v, const int start_column, SparseMatrixsc& D, VectorXs& gdotD )
//{
//  assert( start_column >= 0 ); assert( start_column < D.cols() ); assert( start_column + 1 < D.cols() );
//  assert( q.size() % 12 == 0 ); assert( q.size() == 2 * v.size() );
//
//  const Vector3s n = computeN( q );
//  assert( fabs( n.norm() - 1.0 ) <= 1.0e-10 );
//
//  std::vector<Vector3s> friction_disk( 2 );
//
//  // Compute the relative velocity to use as a direction for the tangent sample
//  friction_disk[0] = computeRelativeVelocityAtCylinderPoint( q, v );
//  // If the relative velocity is zero, any vector will do
//  if( friction_disk[0].cross( n ).squaredNorm() < 1.0e-9 )
//  {
//    friction_disk[0] = FrictionUtilities::orthogonalVector( n );
//  }
//  // Otherwise project out the component along the normal and normalize the relative velocity
//  else
//  {
//    friction_disk[0] = friction_disk[0] - friction_disk[0].dot( n ) * n;
//    friction_disk[0].normalize();
//  }
//  // Invert the tangent vector in order to oppose
//  friction_disk[0] *= -1.0;
//  assert( fabs( friction_disk[0].norm() - 1.0 ) < 1.0e-6 );
//  assert( fabs( friction_disk[0].dot( n ) ) < 1.0e-6 );
//
//  // Create a second orthogonal sample in the tangent plane
//  friction_disk[1] = friction_disk[0].cross( n ).normalized(); // Don't need to normalize but it won't hurt
//  assert( fabs( friction_disk[1].norm() - 1.0 ) < 1.0e-6 );
//
//  // Compute the displacement from the center of mass to the point of contact
//  assert( m_r > 0.0 );
//  const Vector3s r_world = - m_r * n;
//
//  // For each sample of the friction disk
//  const int nbodies = q.size() / 12;
//  for( int i = 0; i < 2; ++i )
//  {
//    const int cur_col = start_column + i;
//    assert( cur_col >= 0 ); assert( cur_col < D.cols() );
//
//    // Effect on center of mass
//    D.insert( 3 * m_i + 0, cur_col ) = friction_disk[i].x();
//    D.insert( 3 * m_i + 1, cur_col ) = friction_disk[i].y();
//    D.insert( 3 * m_i + 2, cur_col ) = friction_disk[i].z();
//
//    // Effect on orientation
//    const Vector3s ntilde = r_world.cross( friction_disk[i] );
//    D.insert( 3 * ( nbodies + m_i ) + 0, cur_col ) = ntilde.x();
//    D.insert( 3 * ( nbodies + m_i ) + 1, cur_col ) = ntilde.y();
//    D.insert( 3 * ( nbodies + m_i ) + 2, cur_col ) = ntilde.z();
//
//    // Relative velocity contribution from kinematic scripting
//    assert( cur_col < gdotD.size() );
//    gdotD( cur_col ) = - friction_disk[i].dot( computeCylinderCollisionPointVelocity( q ) );
//  }
//}
//
int StaticCylinderBodyConstraint::impactStencilSize() const
{
  return 6;
}

int StaticCylinderBodyConstraint::frictionStencilSize() const
{
  return 6;
}

//void StaticCylinderSphereConstraint::getSimulatedBodyIndices( std::pair<int,int>& bodies ) const
//{
//  bodies.first = m_i;
//  bodies.second = -1;
//}
//
//void StaticCylinderSphereConstraint::computeFrictionMask( const int nbodies, VectorXs& friction_mask ) const
//{
//  std::cerr << "StaticCylinderSphereConstraint::computeFrictionMask not implemented." << std::endl;
//  std::exit( EXIT_FAILURE );
////  assert( 3 * m_i + 2 < friction_mask.size() );
////  assert( 3 * ( m_i + nbodies ) + 2 < friction_mask.size() );
////
////  friction_mask.segment<3>( 3 * m_i ).setConstant( 1.0 );
////  friction_mask.segment<3>( 3 * ( m_i + nbodies ) ).setConstant( 1.0 );
//}
//
//void StaticCylinderSphereConstraint::getBodyIndices( std::pair<int,int>& bodies ) const
//{
//  this->getSimulatedBodyIndices( bodies );
//}

void StaticCylinderBodyConstraint::evalKinematicNormalRelVel( const VectorXs& q, const int strt_idx, VectorXs& gdotN ) const
{
  assert( strt_idx >= 0 ); assert( strt_idx < gdotN.size() );

  const Vector3s n{ computeN( q ) };
  assert( fabs( n.norm() - 1.0 ) <= 1.0e-6 );
  assert( fabs( n.dot( m_cyl.axis() ) ) <= 1.0e-6 );

  gdotN( strt_idx ) = - n.dot( computeCylinderCollisionPointVelocity( q ) );
}

bool StaticCylinderBodyConstraint::conservesTranslationalMomentum() const
{
  return false;
}

bool StaticCylinderBodyConstraint::conservesAngularMomentumUnderImpact() const
{
  return false;
}

bool StaticCylinderBodyConstraint::conservesAngularMomentumUnderImpactAndFriction() const
{
  return false;
}

std::string StaticCylinderBodyConstraint::name() const
{
  return "static_cylinder_body";
}

Vector3s StaticCylinderBodyConstraint::computeN( const VectorXs& q ) const
{
  const Vector3s x_body{ q.segment<3>( 3 * m_body_index ) };
  const Vector3s axis{ m_cyl.axis() };
  Vector3s n{ - ( x_body - m_cyl.x() - axis.dot( x_body - m_cyl.x() ) * axis ) };
  assert( n.norm() > 0.0 );
  return n / n.norm();
}

Vector3s StaticCylinderBodyConstraint::computeCylinderCollisionPointVelocity( const VectorXs& q ) const
{
  // Vector perpendicular to axis in direction of particle
  const Vector3s n{ -computeN( q ) };
  assert( fabs( n.norm() - 1.0 ) <= 1.0e-6 );
  assert( fabs( n.dot( m_cyl.axis() ) ) <= 1.0e-6 );

  // Closest point on axis to the particle
  const Vector3s p{ q.segment<3>( 3 * m_body_index ) - m_cyl.x() - n.dot( q.segment<3>( 3 * m_body_index ) - m_cyl.x() ) * n };
  assert( ( ( p - m_cyl.x() ).cross( m_cyl.axis() ) ).norm() <= 1.0e-6  );

  // Closest point on cylinder to the particle
  const Vector3s r{ p + m_cyl.r() * n };

  return m_cyl.v() + m_cyl.omega().cross( r );
}

VectorXs StaticCylinderBodyConstraint::computeKinematicRelativeVelocity( const VectorXs& q, const VectorXs& v ) const
{
  return computeCylinderCollisionPointVelocity( q );
}

//Vector3s StaticCylinderSphereConstraint::computeRelativeVelocityAtCylinderPoint( const VectorXs& q, const VectorXs& v ) const
//{
//  assert( v.size() % 6 == 0 ); assert( v.size() / 2 + 3 * m_i + 2 < v.size() );
//
//  const int nbodies = v.size() / 6;
//
//  const Vector3s r_sphere = - m_r * computeN( q );
//
//  // v + omega x r
//  return v.segment<3>( 3 * m_i ) + v.segment<3>( 3 * ( nbodies + m_i ) ).cross( r_sphere ) - computeCylinderCollisionPointVelocity( q );
//}

//void StaticCylinderSphereConstraint::getWorldSpaceContactPoint( const VectorXs& q, VectorXs& contact_point )
//{
//  contact_point = q.segment<3>( 3 * m_i ) - m_r * computeN( q );
//}

//void StaticCylinderSphereConstraint::getWorldSpaceContactNormal( const VectorXs& q, VectorXs& contact_normal )
//{
//  contact_normal = computeN( q );
//}

//unsigned StaticCylinderSphereConstraint::getStaticObjectIndex() const
//{
//  return m_cylinder_index;
//}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <wangle/acceptor/EvbHandshakeHelper.h>

namespace wangle {

void EvbHandshakeHelper::start(
    folly::AsyncSSLSocket::UniquePtr sock,
    AcceptorHandshakeHelper::Callback* callback) noexcept {
  auto transition =
      tryTransition(HandshakeState::Invalid, HandshakeState::Started);
  if (!transition.first) {
    VLOG(5) << "Ignoring call to start(), since state is currently "
            << static_cast<unsigned>(transition.second);
  }

  callback_ = callback;
  originalEvb_ = sock->getEventBase();
  CHECK(originalEvb_);

  sock->detachEventBase();
  handshakeEvb_->runInEventBaseThread(
      [ this, sock = std::move(sock) ]() mutable {
        sock->attachEventBase(handshakeEvb_);
        helper_->start(std::move(sock), this);
      });
}

void EvbHandshakeHelper::dropConnection(SSLErrorEnum reason) {
  CHECK(originalEvb_);
  originalEvb_->dcheckIsInEventBaseThread();

  auto transition =
      tryTransition(HandshakeState::Started, HandshakeState::Dropped);

  // Regardless of whether or not we win the race or not, we will set
  // dropConnectionGuard_ (see case 2) to let a potential C' know that the
  // connection was dropped. C', seeing this, is responsible for clearing
  // the dropConnectionGuard.
  dropConnectionGuard_.emplace(this);
  callback_->connectionError(
      nullptr,
      folly::make_exception_wrapper<std::runtime_error>("connection dropped"),
      reason);

  if (transition.first) {
    // If we win the race to update the state, though, we are responsible
    // for ensuring that dropConnection() is called on the handshake thread,
    // and we are also the one responsible for clearing the dropConnectionGuard_
    // that we set earlier.
    handshakeEvb_->runInEventBaseThread([this, reason] {
      VLOG(5) << "callback has not been received. dropConnection "
              << "calling underlying helper";

      helper_->dropConnection(reason);

      // We need to ensure that the transport is destroyed in the handshake
      // thread since the transport is currently attached to the handshake's
      // event base.
      helper_.reset();

      originalEvb_->runInEventBaseThread(
          [this] { dropConnectionGuard_.clear(); });
    });
  }
}

void EvbHandshakeHelper::connectionReady(
    folly::AsyncTransportWrapper::UniquePtr transport,
    std::string nextProtocol,
    SecureTransportType secureTransportType,
    folly::Optional<SSLErrorEnum> sslErr) noexcept {
  DCHECK_EQ(transport->getEventBase(), handshakeEvb_);

  auto transition =
      tryTransition(HandshakeState::Started, HandshakeState::Callback);
  if (!transition.first) {
    VLOG(5) << "Ignoring call to connectionReady(), expected state to be "
            << static_cast<unsigned>(HandshakeState::Started)
            << " but actual state was "
            << static_cast<unsigned>(transition.second);
    return;
  }

  transport->detachEventBase();

  originalEvb_->runInEventBaseThread([
    this,
    secureTransportType,
    sslErr,
    transport = std::move(transport),
    nextProtocol = std::move(nextProtocol)
  ]() mutable {
    DCHECK(callback_);
    VLOG(5) << "calling underlying callback connectionReady";
    transport->attachEventBase(originalEvb_);

    // If a dropConnection call occured by the time this lambda runs, we don't
    // want to fire the callback. (See Case 2)
    if (dropConnectionGuard_.hasValue()) {
      dropConnectionGuard_.clear();
      return;
    }

    callback_->connectionReady(
        std::move(transport),
        std::move(nextProtocol),
        secureTransportType,
        sslErr);
  });
}

void EvbHandshakeHelper::connectionError(
    folly::AsyncTransportWrapper* transport,
    folly::exception_wrapper ex,
    folly::Optional<SSLErrorEnum> sslErr) noexcept {
  DCHECK(transport->getEventBase() == handshakeEvb_);

  auto transition =
      tryTransition(HandshakeState::Started, HandshakeState::Callback);
  if (!transition.first) {
    VLOG(5) << "Ignoring call to connectionError(), expected state to be "
            << static_cast<unsigned>(HandshakeState::Started)
            << " but actual state was "
            << static_cast<unsigned>(transition.second);
    return;
  }

  helper_.reset();
  originalEvb_->runInEventBaseThread(
      [this, sslErr, ex = std::move(ex)]() mutable {
        DCHECK(callback_);
        VLOG(5) << "calling underlying callback connectionError";

        // If a dropConnection call occured by the time this lambda runs, we
        // don't want to fire the callback. (See Case 2)
        if (dropConnectionGuard_.hasValue()) {
          dropConnectionGuard_.clear();
          return;
        }
        callback_->connectionError(nullptr, std::move(ex), sslErr);
      });
}

std::pair<bool, EvbHandshakeHelper::HandshakeState>
EvbHandshakeHelper::tryTransition(
    HandshakeState expected,
    HandshakeState next) {
  bool res = state_.compare_exchange_strong(expected, next);
  return std::make_pair(res, expected);
}

EvbHandshakeHelper::~EvbHandshakeHelper() {
  VLOG(5) << "evbhandshakehelper is destroyed";
}
}
<commit_msg>Fix a race in EvbHandshakeHelper<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <wangle/acceptor/EvbHandshakeHelper.h>

namespace wangle {

void EvbHandshakeHelper::start(
    folly::AsyncSSLSocket::UniquePtr sock,
    AcceptorHandshakeHelper::Callback* callback) noexcept {
  auto transition =
      tryTransition(HandshakeState::Invalid, HandshakeState::Started);
  if (!transition.first) {
    VLOG(5) << "Ignoring call to start(), since state is currently "
            << static_cast<unsigned>(transition.second);
  }

  callback_ = callback;
  originalEvb_ = sock->getEventBase();
  CHECK(originalEvb_);

  sock->detachEventBase();
  originalEvb_->runInLoop(
      [this, sock = std::move(sock)]() mutable {
        handshakeEvb_->runInEventBaseThread(
            [this, sock = std::move(sock)]() mutable {
              sock->attachEventBase(handshakeEvb_);
              helper_->start(std::move(sock), this);
            });
      },
      /* thisIteration = */ true);
}

void EvbHandshakeHelper::dropConnection(SSLErrorEnum reason) {
  CHECK(originalEvb_);
  originalEvb_->dcheckIsInEventBaseThread();

  auto transition =
      tryTransition(HandshakeState::Started, HandshakeState::Dropped);

  // Regardless of whether or not we win the race or not, we will set
  // dropConnectionGuard_ (see case 2) to let a potential C' know that the
  // connection was dropped. C', seeing this, is responsible for clearing
  // the dropConnectionGuard.
  dropConnectionGuard_.emplace(this);
  callback_->connectionError(
      nullptr,
      folly::make_exception_wrapper<std::runtime_error>("connection dropped"),
      reason);

  if (transition.first) {
    // If we win the race to update the state, though, we are responsible
    // for ensuring that dropConnection() is called on the handshake thread,
    // and we are also the one responsible for clearing the dropConnectionGuard_
    // that we set earlier.
    handshakeEvb_->runInEventBaseThread([this, reason] {
      VLOG(5) << "callback has not been received. dropConnection "
              << "calling underlying helper";

      helper_->dropConnection(reason);

      // We need to ensure that the transport is destroyed in the handshake
      // thread since the transport is currently attached to the handshake's
      // event base.
      helper_.reset();

      originalEvb_->runInEventBaseThread(
          [this] { dropConnectionGuard_.clear(); });
    });
  }
}

void EvbHandshakeHelper::connectionReady(
    folly::AsyncTransportWrapper::UniquePtr transport,
    std::string nextProtocol,
    SecureTransportType secureTransportType,
    folly::Optional<SSLErrorEnum> sslErr) noexcept {
  DCHECK_EQ(transport->getEventBase(), handshakeEvb_);

  auto transition =
      tryTransition(HandshakeState::Started, HandshakeState::Callback);
  if (!transition.first) {
    VLOG(5) << "Ignoring call to connectionReady(), expected state to be "
            << static_cast<unsigned>(HandshakeState::Started)
            << " but actual state was "
            << static_cast<unsigned>(transition.second);
    return;
  }

  transport->detachEventBase();

  handshakeEvb_->runInLoop(
      [this,
       secureTransportType,
       sslErr,
       transport = std::move(transport),
       nextProtocol = std::move(nextProtocol)]() mutable {
        originalEvb_->runInEventBaseThread(
            [this,
             secureTransportType,
             sslErr,
             transport = std::move(transport),
             nextProtocol = std::move(nextProtocol)]() mutable {
              DCHECK(callback_);
              VLOG(5) << "calling underlying callback connectionReady";
              transport->attachEventBase(originalEvb_);

              // If a dropConnection call occured by the time this lambda runs,
              // we don't want to fire the callback. (See Case 2)
              if (dropConnectionGuard_.hasValue()) {
                dropConnectionGuard_.clear();
                return;
              }

              callback_->connectionReady(
                  std::move(transport),
                  std::move(nextProtocol),
                  secureTransportType,
                  sslErr);
            });
      },
      /* thisIteration = */ true);
}

void EvbHandshakeHelper::connectionError(
    folly::AsyncTransportWrapper* transport,
    folly::exception_wrapper ex,
    folly::Optional<SSLErrorEnum> sslErr) noexcept {
  DCHECK(transport->getEventBase() == handshakeEvb_);

  auto transition =
      tryTransition(HandshakeState::Started, HandshakeState::Callback);
  if (!transition.first) {
    VLOG(5) << "Ignoring call to connectionError(), expected state to be "
            << static_cast<unsigned>(HandshakeState::Started)
            << " but actual state was "
            << static_cast<unsigned>(transition.second);
    return;
  }

  helper_.reset();
  originalEvb_->runInEventBaseThread(
      [this, sslErr, ex = std::move(ex)]() mutable {
        DCHECK(callback_);
        VLOG(5) << "calling underlying callback connectionError";

        // If a dropConnection call occured by the time this lambda runs, we
        // don't want to fire the callback. (See Case 2)
        if (dropConnectionGuard_.hasValue()) {
          dropConnectionGuard_.clear();
          return;
        }
        callback_->connectionError(nullptr, std::move(ex), sslErr);
      });
}

std::pair<bool, EvbHandshakeHelper::HandshakeState>
EvbHandshakeHelper::tryTransition(
    HandshakeState expected,
    HandshakeState next) {
  bool res = state_.compare_exchange_strong(expected, next);
  return std::make_pair(res, expected);
}

EvbHandshakeHelper::~EvbHandshakeHelper() {
  VLOG(5) << "evbhandshakehelper is destroyed";
}
}
<|endoftext|>


<commit_before>/*******************************************************************************
*  Code contributed to the webinos project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012 Samsung Electronics(UK) Ltd
*
******************************************************************************/
#include <v8.h>
#include <node.h>
#include <csignal>
#include <string>

extern "C"{
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <termios.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <assert.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>

#include <obexftp/obexftp.h>
#include <obexftp/client.h>
#include <obexftp/uuid.h>
}

using namespace node;
using namespace v8;
using namespace std;

#define MAXPATHLEN 248

::sig_atomic_t io_canceled_=0;
obexftp_client_t *cli = NULL;

typedef struct {
  int dev_id;
  int sock;
  int ctl; //RFCOMM socket
  int channel; // RFCOMM channel
}BTDevice;

typedef struct {
  char *address;
  char *name;
} BlueToothData;

class BTDiscovery: ObjectWrap
{
  private:

	//Persistent< Value > myval;

  public:

	static void sig_hup(int sig)
	{
		return;
	}

	static void sig_term(int sig)
	{
		io_canceled_ = 1;
	}

  static Persistent<FunctionTemplate> s_ct;

  static void Init(Handle<Object> target)
  {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(New);

    s_ct = Persistent<FunctionTemplate>::New(t);
    s_ct->InstanceTemplate()->SetInternalFieldCount(1);
    s_ct->SetClassName(String::NewSymbol("BT"));

    NODE_SET_PROTOTYPE_METHOD(s_ct, "scan_device", Scan_device);

    NODE_SET_PROTOTYPE_METHOD(s_ct, "file_transfer", File_transfer);

    target->Set(String::NewSymbol("bluetooth"), s_ct->GetFunction());
  }

  BTDiscovery()
  {
  }

  ~BTDiscovery()
  {
  }

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;
    BTDiscovery* bd = new BTDiscovery();
    bd->Wrap(args.This());
    return args.This();
  }

  static Handle<Value> Scan_device(const Arguments& args)
  {
    HandleScope scope;
    Local<Object> result =  Object::New();

    // Convert first argument to V8 String
    v8::String::Utf8Value v8str(args[0]);

    v8::Handle<v8::Array> result1 = v8::Array::New(12);

    BTDevice bt_dev;
    int num_rsp;
    inquiry_info *ii;

    char dev_addr[19] = { 0 };  // device address as string
    char dev_name[248] = { 0 }; // device name
    char dev_name_tmp[248] = { 0 }; // device name

    uuid_t svc_uuid;
    int err;
    bdaddr_t target;
    bdaddr_t source;
    sdp_list_t *response_list = NULL, *search_list, *attrid_list;
    sdp_session_t *session = 0;
    uint32_t serv_class = 0;
    int i;

   //scan_device

    bt_dev.dev_id = hci_get_route(NULL);
    bt_dev.sock = hci_open_dev( bt_dev.dev_id );

    if (bt_dev.dev_id < 0 || bt_dev.sock < 0)
    {
      perror("opening bluetooth socket");
      printf("bluetooth: releasing object\n");
    }

    int len  = 4;  // search time is len * 1.28 seconds
    int max_rsp = 255; // max number of devices to report
    int flags = IREQ_CACHE_FLUSH;

    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
    assert(ii);

    // okay fire up the bluetooth scan for len * 1.28 seconds
    // or 255 devices, whichever happens soonest
    num_rsp = hci_inquiry(bt_dev.dev_id, len, max_rsp, NULL, &ii, flags);

    printf("found %d bluetooth devices\n", num_rsp);

    // end - scan_device

    int j = 0;

    for (i = 0; i < num_rsp; i++)
    {
      target = (ii+i)->bdaddr;
      str2ba("0:0:0:0:0:0", &source);

      if (!strncasecmp(*v8str, "0x", 2))
      {
    	int num;
	    /* This is a UUID16, just convert to int */
	    sscanf(*v8str + 2, "%X", &num);
	    serv_class = num;
      }

      if (serv_class)
      {
    	if (serv_class & 0xffff0000)
	    {
	      sdp_uuid32_create(&svc_uuid, serv_class);
		  printf("Creating a 32 bit uuid\n");
	    }
	    else
	    {
		  uint16_t class16 = serv_class & 0xffff;
		  sdp_uuid16_create(&svc_uuid, class16);
	    }
      }
      else
      {
        printf("service class is not correct\n");
        return args.This();
      }
    // connect to the SDP server running on the remote machine

      // connect to the SDP server running on the remote machine
      session = sdp_connect( &source, &target, SDP_RETRY_IF_BUSY );
      if (session == (sdp_session_t *)NULL)
      {
        printf("session for device to connect is not available, go to next device\n");
      }
      else
      {
        search_list = sdp_list_append( NULL, &svc_uuid );

        // specify that we want a list of all the matching applications' attributes
        uint32_t range = 0x0000ffff;
        attrid_list = sdp_list_append( NULL, &range );

        // get a list of service records that have the specified UUID, e.g. 0x1106
        err = sdp_service_search_attr_req( session, search_list, \
        SDP_ATTR_REQ_RANGE, attrid_list, &response_list);

        sdp_list_t *r = response_list;

        // go through each of the service records

      for (; r; r = r->next )
      {
    	ba2str(&(ii+i)->bdaddr, dev_addr);
	    strcpy(dev_name, "[unknown]");

        if(hci_read_remote_name(bt_dev.sock, &(ii+i)->bdaddr,
		 sizeof(dev_name)-1, dev_name, 0) < 0);

        printf("bluetooth device name: %s\n", dev_name);
        printf("bluetooth device address: %s\n", dev_addr);

        if(strcmp(dev_name, dev_name_tmp))
        {
          result1->Set(v8::Number::New(j), v8::String::New(dev_name));
          result1->Set(v8::Number::New(++j), v8::String::New(dev_addr));
          result1->Set(v8::Number::New(++j), v8::String::New("\n"));
          j++;
        }

        strcpy(dev_name_tmp, dev_name);

        sdp_record_t *rec = (sdp_record_t*) r->data;
        sdp_record_print(rec);
        //printf("Service RecHandle: 0x%x\n", rec->handle);

        sdp_list_t *proto_list;

	    // get a list of the protocol sequences
	    if( sdp_get_access_protos( rec, &proto_list ) == 0 )
	    {
          sdp_list_t *p = proto_list;

          // go through each protocol sequence
          for( ; p ; p = p->next )
          {
            sdp_list_t *pds = (sdp_list_t*)p->data;

            // go through each protocol list of the protocol sequence
            for( ; pds ; pds = pds->next )
            {
              // check the protocol attributes
              sdp_data_t *d = (sdp_data_t*)pds->data;
              int proto = 0;
              for( ; d; d = d->next )
              {
                switch( d->dtd )
                {
                  case SDP_UUID16:
                  case SDP_UUID32:
                  case SDP_UUID128:
                    proto = sdp_uuid_to_proto( &d->val.uuid );
                  break;
                  case SDP_UINT8:
                    if( proto == RFCOMM_UUID )
                      //printf("rfcomm channel: %d\n",d->val.int8);
                      bt_dev.channel = d->val.int8;
                  break;
                }
              }
            }
            sdp_list_free( (sdp_list_t*)p->data, 0 );
          }
          sdp_list_free( proto_list, 0 );
        }

        sdp_record_free( rec );

      }
     }
      sdp_close(session);
    }

  free( ii );
  close(bt_dev.sock);

  return result1;

  }

  static Handle<Value> File_transfer(const Arguments& args)
  {
    HandleScope scope;
    Local<Object> result =  Object::New();

    v8::String::Utf8Value v8arg0(args[0]);
    v8::String::Utf8Value v8arg1(args[1]);
    v8::Handle<v8::Array> result1 = v8::Array::New(12);

    //static obexftp_client_t *cli = NULL;
    static const char *src_dev = NULL;
    static int transport = OBEX_TRANS_BLUETOOTH;
    char *device = *v8arg0;
    static int channel = 4;

    static const char *use_uuid = (const char *)UUID_FBS;
    static int use_uuid_len = sizeof(UUID_FBS);

    transport = OBEX_TRANS_BLUETOOTH;

    if(cli == NULL)
    {
	int ret, retry;
	cli = obexftp_open (transport, NULL, NULL, NULL);

	if(cli == NULL)
	{
		fprintf(stderr, "Error opening obexftp-client\n");
	        return args.This();
	}

    	for (retry = 0; retry < 3; retry++)
   	{
		ret = obexftp_connect_src(cli, src_dev, device, channel, (const uint8_t *)use_uuid, use_uuid_len);
		if (ret >= 0)
		{
			printf("connect successful\n");
		      	//goto listfolder;
			char *cmd = *v8arg1;
			if(strcmp(cmd, "folder")== 0)
			{
				stat_entry_t *ent;
				void *dir;
				dir = obexftp_opendir(cli, "/");

				int j;
				j = 0;

				while ((ent = obexftp_readdir(dir)) != NULL)
				{
					stat_entry_t *st;
					st = obexftp_stat(cli, ent->name);
					if (!st) continue;
					printf("%d %s%s\n", st->size, ent->name,
					ent->mode&S_IFDIR?"/":"");
					result1->Set(v8::Number::New(j), v8::String::New(ent->name));
				 	j++;
				}
				obexftp_closedir(dir);
			}
			if(strcmp(cmd, "file")== 0)
			{
				v8::String::Utf8Value v8arg2(args[2]);
				int ret = obexftp_list(cli, NULL, *v8arg2);

				if (ret < 0) {
				fprintf(stderr, "Error getting a folder listing\n");
				}
				else
				{
			  		if(cli->buf_data)
			  		{
						printf("come to file list\n");
						result1->Set(v8::Number::New(0), v8::String::New((char*)cli->buf_data));
				        }
					//list folder
			  		else
			  		{
						printf("comes to nested folder\n");
						stat_entry_t *ent;
						void *dir = obexftp_opendir(cli, *v8arg2);

						int j = 0;
						while ((ent = obexftp_readdir(dir)) != NULL)
						{
							printf("nested folder 1\n");
							stat_entry_t *st;
							st = obexftp_stat(cli, ent->name);
							if (!st) continue;
							char* name = strcat(*v8arg1, ent->name);
							printf("name is: %s\n", name);
							result1->Set(v8::Number::New(j), v8::String::New(name));
							j++;
						}
						obexftp_closedir(dir);
					}
				}
			}
			if(strcmp(cmd, "transfer")== 0)
			{
				//goto transfer;
				v8::String::Utf8Value v8arg2(args[2]);
				v8::String::Utf8Value v8arg3(args[3]);
    				printf("v8arg2 = %s\n", *v8arg2);
			    	printf("v8arg3 = %s\n", *v8arg3);

			    	int ret = obexftp_get(cli, *v8arg3, *v8arg2);

				if (ret < 0) {
					fprintf(stderr, "Error getting a file\n");
				}
				else
				{
					printf("get file successful!");
				}
				result1->Set(v8::Number::New(0), v8::Integer::New(ret));
			}
		}
	}

    }

 	obexftp_close(cli);
	cli = NULL;
    return result1;
  }
};
Persistent<FunctionTemplate> BTDiscovery::s_ct;

extern "C" {
  static void init (Handle<Object> target)
  {
	  BTDiscovery::Init(target);
  }

  NODE_MODULE(bluetooth, init);
}
<commit_msg>Fix warning about unused "result" variable<commit_after>/*******************************************************************************
*  Code contributed to the webinos project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012 Samsung Electronics(UK) Ltd
*
******************************************************************************/
#include <v8.h>
#include <node.h>
#include <csignal>
#include <string>

extern "C"{
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <termios.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <assert.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>

#include <obexftp/obexftp.h>
#include <obexftp/client.h>
#include <obexftp/uuid.h>
}

using namespace node;
using namespace v8;
using namespace std;

#define MAXPATHLEN 248

::sig_atomic_t io_canceled_=0;
obexftp_client_t *cli = NULL;

typedef struct {
  int dev_id;
  int sock;
  int ctl; //RFCOMM socket
  int channel; // RFCOMM channel
}BTDevice;

typedef struct {
  char *address;
  char *name;
} BlueToothData;

class BTDiscovery: ObjectWrap
{
  private:

	//Persistent< Value > myval;

  public:

	static void sig_hup(int sig)
	{
		return;
	}

	static void sig_term(int sig)
	{
		io_canceled_ = 1;
	}

  static Persistent<FunctionTemplate> s_ct;

  static void Init(Handle<Object> target)
  {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(New);

    s_ct = Persistent<FunctionTemplate>::New(t);
    s_ct->InstanceTemplate()->SetInternalFieldCount(1);
    s_ct->SetClassName(String::NewSymbol("BT"));

    NODE_SET_PROTOTYPE_METHOD(s_ct, "scan_device", Scan_device);

    NODE_SET_PROTOTYPE_METHOD(s_ct, "file_transfer", File_transfer);

    target->Set(String::NewSymbol("bluetooth"), s_ct->GetFunction());
  }

  BTDiscovery()
  {
  }

  ~BTDiscovery()
  {
  }

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;
    BTDiscovery* bd = new BTDiscovery();
    bd->Wrap(args.This());
    return args.This();
  }

  static Handle<Value> Scan_device(const Arguments& args)
  {
    HandleScope scope;

    // Convert first argument to V8 String
    v8::String::Utf8Value v8str(args[0]);

    v8::Handle<v8::Array> result1 = v8::Array::New(12);

    BTDevice bt_dev;
    int num_rsp;
    inquiry_info *ii;

    char dev_addr[19] = { 0 };  // device address as string
    char dev_name[248] = { 0 }; // device name
    char dev_name_tmp[248] = { 0 }; // device name

    uuid_t svc_uuid;
    int err;
    bdaddr_t target;
    bdaddr_t source;
    sdp_list_t *response_list = NULL, *search_list, *attrid_list;
    sdp_session_t *session = 0;
    uint32_t serv_class = 0;
    int i;

   //scan_device

    bt_dev.dev_id = hci_get_route(NULL);
    bt_dev.sock = hci_open_dev( bt_dev.dev_id );

    if (bt_dev.dev_id < 0 || bt_dev.sock < 0)
    {
      perror("opening bluetooth socket");
      printf("bluetooth: releasing object\n");
    }

    int len  = 4;  // search time is len * 1.28 seconds
    int max_rsp = 255; // max number of devices to report
    int flags = IREQ_CACHE_FLUSH;

    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
    assert(ii);

    // okay fire up the bluetooth scan for len * 1.28 seconds
    // or 255 devices, whichever happens soonest
    num_rsp = hci_inquiry(bt_dev.dev_id, len, max_rsp, NULL, &ii, flags);

    printf("found %d bluetooth devices\n", num_rsp);

    // end - scan_device

    int j = 0;

    for (i = 0; i < num_rsp; i++)
    {
      target = (ii+i)->bdaddr;
      str2ba("0:0:0:0:0:0", &source);

      if (!strncasecmp(*v8str, "0x", 2))
      {
    	int num;
	    /* This is a UUID16, just convert to int */
	    sscanf(*v8str + 2, "%X", &num);
	    serv_class = num;
      }

      if (serv_class)
      {
    	if (serv_class & 0xffff0000)
	    {
	      sdp_uuid32_create(&svc_uuid, serv_class);
		  printf("Creating a 32 bit uuid\n");
	    }
	    else
	    {
		  uint16_t class16 = serv_class & 0xffff;
		  sdp_uuid16_create(&svc_uuid, class16);
	    }
      }
      else
      {
        printf("service class is not correct\n");
        return args.This();
      }
    // connect to the SDP server running on the remote machine

      // connect to the SDP server running on the remote machine
      session = sdp_connect( &source, &target, SDP_RETRY_IF_BUSY );
      if (session == (sdp_session_t *)NULL)
      {
        printf("session for device to connect is not available, go to next device\n");
      }
      else
      {
        search_list = sdp_list_append( NULL, &svc_uuid );

        // specify that we want a list of all the matching applications' attributes
        uint32_t range = 0x0000ffff;
        attrid_list = sdp_list_append( NULL, &range );

        // get a list of service records that have the specified UUID, e.g. 0x1106
        err = sdp_service_search_attr_req( session, search_list, \
        SDP_ATTR_REQ_RANGE, attrid_list, &response_list);

        sdp_list_t *r = response_list;

        // go through each of the service records

      for (; r; r = r->next )
      {
    	ba2str(&(ii+i)->bdaddr, dev_addr);
	    strcpy(dev_name, "[unknown]");

        if(hci_read_remote_name(bt_dev.sock, &(ii+i)->bdaddr,
		 sizeof(dev_name)-1, dev_name, 0) < 0);

        printf("bluetooth device name: %s\n", dev_name);
        printf("bluetooth device address: %s\n", dev_addr);

        if(strcmp(dev_name, dev_name_tmp))
        {
          result1->Set(v8::Number::New(j), v8::String::New(dev_name));
          result1->Set(v8::Number::New(++j), v8::String::New(dev_addr));
          result1->Set(v8::Number::New(++j), v8::String::New("\n"));
          j++;
        }

        strcpy(dev_name_tmp, dev_name);

        sdp_record_t *rec = (sdp_record_t*) r->data;
        sdp_record_print(rec);
        //printf("Service RecHandle: 0x%x\n", rec->handle);

        sdp_list_t *proto_list;

	    // get a list of the protocol sequences
	    if( sdp_get_access_protos( rec, &proto_list ) == 0 )
	    {
          sdp_list_t *p = proto_list;

          // go through each protocol sequence
          for( ; p ; p = p->next )
          {
            sdp_list_t *pds = (sdp_list_t*)p->data;

            // go through each protocol list of the protocol sequence
            for( ; pds ; pds = pds->next )
            {
              // check the protocol attributes
              sdp_data_t *d = (sdp_data_t*)pds->data;
              int proto = 0;
              for( ; d; d = d->next )
              {
                switch( d->dtd )
                {
                  case SDP_UUID16:
                  case SDP_UUID32:
                  case SDP_UUID128:
                    proto = sdp_uuid_to_proto( &d->val.uuid );
                  break;
                  case SDP_UINT8:
                    if( proto == RFCOMM_UUID )
                      //printf("rfcomm channel: %d\n",d->val.int8);
                      bt_dev.channel = d->val.int8;
                  break;
                }
              }
            }
            sdp_list_free( (sdp_list_t*)p->data, 0 );
          }
          sdp_list_free( proto_list, 0 );
        }

        sdp_record_free( rec );

      }
     }
      sdp_close(session);
    }

  free( ii );
  close(bt_dev.sock);

  return result1;

  }

  static Handle<Value> File_transfer(const Arguments& args)
  {
    HandleScope scope;
    Local<Object> result =  Object::New();

    v8::String::Utf8Value v8arg0(args[0]);
    v8::String::Utf8Value v8arg1(args[1]);
    v8::Handle<v8::Array> result1 = v8::Array::New(12);

    //static obexftp_client_t *cli = NULL;
    static const char *src_dev = NULL;
    static int transport = OBEX_TRANS_BLUETOOTH;
    char *device = *v8arg0;
    static int channel = 4;

    static const char *use_uuid = (const char *)UUID_FBS;
    static int use_uuid_len = sizeof(UUID_FBS);

    transport = OBEX_TRANS_BLUETOOTH;

    if(cli == NULL)
    {
	int ret, retry;
	cli = obexftp_open (transport, NULL, NULL, NULL);

	if(cli == NULL)
	{
		fprintf(stderr, "Error opening obexftp-client\n");
	        return args.This();
	}

    	for (retry = 0; retry < 3; retry++)
   	{
		ret = obexftp_connect_src(cli, src_dev, device, channel, (const uint8_t *)use_uuid, use_uuid_len);
		if (ret >= 0)
		{
			printf("connect successful\n");
		      	//goto listfolder;
			char *cmd = *v8arg1;
			if(strcmp(cmd, "folder")== 0)
			{
				stat_entry_t *ent;
				void *dir;
				dir = obexftp_opendir(cli, "/");

				int j;
				j = 0;

				while ((ent = obexftp_readdir(dir)) != NULL)
				{
					stat_entry_t *st;
					st = obexftp_stat(cli, ent->name);
					if (!st) continue;
					printf("%d %s%s\n", st->size, ent->name,
					ent->mode&S_IFDIR?"/":"");
					result1->Set(v8::Number::New(j), v8::String::New(ent->name));
				 	j++;
				}
				obexftp_closedir(dir);
			}
			if(strcmp(cmd, "file")== 0)
			{
				v8::String::Utf8Value v8arg2(args[2]);
				int ret = obexftp_list(cli, NULL, *v8arg2);

				if (ret < 0) {
				fprintf(stderr, "Error getting a folder listing\n");
				}
				else
				{
			  		if(cli->buf_data)
			  		{
						printf("come to file list\n");
						result1->Set(v8::Number::New(0), v8::String::New((char*)cli->buf_data));
				        }
					//list folder
			  		else
			  		{
						printf("comes to nested folder\n");
						stat_entry_t *ent;
						void *dir = obexftp_opendir(cli, *v8arg2);

						int j = 0;
						while ((ent = obexftp_readdir(dir)) != NULL)
						{
							printf("nested folder 1\n");
							stat_entry_t *st;
							st = obexftp_stat(cli, ent->name);
							if (!st) continue;
							char* name = strcat(*v8arg1, ent->name);
							printf("name is: %s\n", name);
							result1->Set(v8::Number::New(j), v8::String::New(name));
							j++;
						}
						obexftp_closedir(dir);
					}
				}
			}
			if(strcmp(cmd, "transfer")== 0)
			{
				//goto transfer;
				v8::String::Utf8Value v8arg2(args[2]);
				v8::String::Utf8Value v8arg3(args[3]);
    				printf("v8arg2 = %s\n", *v8arg2);
			    	printf("v8arg3 = %s\n", *v8arg3);

			    	int ret = obexftp_get(cli, *v8arg3, *v8arg2);

				if (ret < 0) {
					fprintf(stderr, "Error getting a file\n");
				}
				else
				{
					printf("get file successful!");
				}
				result1->Set(v8::Number::New(0), v8::Integer::New(ret));
			}
		}
	}

    }

 	obexftp_close(cli);
	cli = NULL;
    return result1;
  }
};
Persistent<FunctionTemplate> BTDiscovery::s_ct;

extern "C" {
  static void init (Handle<Object> target)
  {
	  BTDiscovery::Init(target);
  }

  NODE_MODULE(bluetooth, init);
}
<|endoftext|>


<commit_before>#include <Arduino.h>
#include "SoftwareSerial.h"
#include "A6lib.h"

#ifdef DEBUG
#define log(msg) Serial.print(msg)
#define logln(msg) Serial.println(msg)
#else
#define log(msg)
#define logln(msg)
#endif

#define OK 1
#define NOTOK 2
#define TIMEOUT 3

#define A6_CMD_TIMEOUT 2000

/////////////////////////////////////////////
// Public methods.
//

A6::A6(int transmitPin, int receivePin) {
    A6conn = new SoftwareSerial(receivePin, transmitPin, false, 1024);
    A6conn->setTimeout(100);
}

A6::~A6() {
    delete A6conn;
}

// Initialize the software serial connection and change the baud rate from the
// default (autodetected) to the desired speed.
void A6::begin(long baudRate) {
    // Give the module some time to settle.
    logln("Waiting for the module to initialize...");
    delay(12000);
    logln("Done.");

    A6conn->flush();

    setRate(baudRate);

    // Factory reset.
    A6command("AT&F", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Echo off.
    A6command("ATE0", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set caller ID on.
    A6command("AT+CLIP=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set SMS to text mode.
    A6command("AT+CMGF=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Switch audio to headset.
    enableSpeaker(0);
}

// Reboot the module by setting the specified pin HIGH, then LOW. The pin should
// be connected to a P-MOSFET, not the A6's POWER pin.
void A6::powerCycle(int pin) {
    logln("Power-cycling module...");

    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);

    delay(1000);

    digitalWrite(pin, HIGH);

    // Give the module some time to settle.
    logln("Power-cycle done.");

    A6conn->flush();
}

// Dial a number.
void A6::dial(String number) {
    char buffer[50];

    logln("Dialing number...");

    sprintf(buffer, "ATD%s;", number.c_str());
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Redial the last number.
void A6::redial() {
    logln("Redialing last number...");
    A6command("AT+DLST", "OK", "CONNECT", A6_CMD_TIMEOUT, 2, NULL);
}

// Answer a call.
void A6::answer() {
    A6command("ATA", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Hang up the phone.
void A6::hangUp() {
    A6command("ATH", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Check whether there is an active call.
callInfo A6::checkCallStatus() {
    char number[50];
    String response = "";
    int respStart = 0, matched = 0;
    callInfo cinfo = (const struct callInfo){ 0 };

    // Issue the command and wait for the response.
    A6command("AT+CLCC", "OK", "+CLCC", A6_CMD_TIMEOUT, 2, &response);

    // Parse the response if it contains a valid +CLCC.
    respStart = response.indexOf("+CLCC");
    if (respStart >= 0) {
        matched = sscanf(response.substring(respStart).c_str(), "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", &cinfo.index, &cinfo.direction, &cinfo.state, &cinfo.mode, &cinfo.multiparty, number, &cinfo.type);
        cinfo.number = String(number);
    }

    return cinfo;
}

// Send an SMS.
byte A6::sendSMS(String number, String text) {
    char ctrlZ[2] = { 0x1a, 0x00 };
    char buffer[100];

    if (text.length() > 159) {
        // We can't send messages longer than 160 characters.
        return NOTOK;
    }

    log("Sending SMS to ");
    log(number);
    logln("...");

    sprintf(buffer, "AT+CMGS=\"%s\"", number.c_str());
    A6command(buffer, ">", "yy", A6_CMD_TIMEOUT, 2, NULL);
    delay(100);
    A6conn->println(text.c_str());
    A6conn->println(ctrlZ);
    A6conn->println();

    return OK;
}

// Set the volume for the speaker. level should be a number between 5 and
// 8 inclusive.
void A6::setVol(byte level) {
    char buffer[30];

    // level should be between 5 and 8.
    level = min(max(level, 5), 8);
    sprintf(buffer, "AT+CLVL=%d", level);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Enable the speaker, rather than the headphones. Pass 0 to route audio through
// headphones, 1 through speaker.
void A6::enableSpeaker(byte enable) {
    char buffer[30];

    // enable should be between 0 and 1.
    enable = min(max(enable, 0), 1);
    sprintf(buffer, "AT+SNFS=%d", enable);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

/////////////////////////////////////////////
// Private methods.
//

// Autodetect the connection rate.
int A6::detectRate() {
    int rate = 0;

    // Try to autodetect the rate.
    logln("Autodetecting connection rate...");
    for (int i = 0; i < 8; i++) {
        switch (i) {
        case 0:
            // Try the usual rate first, to speed things up.
            rate = 9600;
            break;
        case 1:
            rate = 1200;
            break;
        case 2:
            rate = 2400;
            break;
        case 3:
            rate = 4800;
            break;
        case 4:
            rate = 19200;
            break;
        case 5:
            rate = 38400;
            break;
        case 6:
            rate = 57600;
            break;
        case 7:
            rate = 115200;
            break;
        }

        A6conn->begin(rate);
        log("Trying rate ");
        log(rate);
        logln("...");

        delay(100);
        if (A6command("AT", "OK", "OK", 2000, 2, NULL) == OK) {
            return rate;
        }
    }

    // Return a default rate.
    return 9600;
}

// Set the A6 baud rate.
void A6::setRate(long baudRate) {
    int rate = detectRate();

    // The rate is already the desired rate, return.
    if (rate == baudRate) return;

    logln("Discovering baud rate...");
    // Change the rate to the requested.
    char buffer[30];
    sprintf(buffer, "AT+IPR=%d", baudRate);
    A6command(buffer, "OK", "+IPR=", A6_CMD_TIMEOUT, 3, NULL);

    logln("Switching to the new rate...");
    // Begin the connection again at the requested rate.
    A6conn->begin(baudRate);
    logln("Rate set.");
}

// Read some data from the A6 in a non-blocking manner.
String A6::read() {
    String reply = "";
    if (A6conn->available()) reply = A6conn->readString();
    return reply;
}

// Issue a command.
byte A6::A6command(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response) {
    byte returnValue = NOTOK;
    byte count = 0;

    // Get rid of any buffered output.
    A6conn->flush();

    while (count < repetitions && returnValue != OK) {
        log("Issuing command: ");
        logln(command);

        A6conn->print(command);
        A6conn->print("\r\n");

        if (A6waitFor(resp1, resp2, timeout, response) == OK) {
            returnValue = OK;
        } else {
            returnValue = NOTOK;
        }
        count++;
    }
    return returnValue;
}

// Wait for responses.
byte A6::A6waitFor(const char *resp1, const char *resp2, int timeout, String *response) {
    unsigned long entry = millis();
    int count = 0;
    String reply = "";
    byte retVal = 99;
    do {
        reply += read();
        yield();
    } while ((reply.indexOf(resp1) + reply.indexOf(resp2) == -2) && millis() - entry < timeout);

    if (reply != "") {
        log("Reply in ");
        log((millis() - entry));
        log(" ms: ");
        logln(reply);
    }

    if (response != NULL) *response = reply;

    if ((millis() - entry) >= timeout) {
        retVal = TIMEOUT;
        logln("Timed out.");
    } else {
        if (reply.indexOf(resp1) + reply.indexOf(resp2) > -2) {
            logln("Reply OK.");
            retVal = OK;
        } else {
            logln("Reply NOT OK.");
            retVal = NOTOK;
        }
    }
    return retVal;
}
<commit_msg>Change to just CR.<commit_after>#include <Arduino.h>
#include "SoftwareSerial.h"
#include "A6lib.h"

#ifdef DEBUG
#define log(msg) Serial.print(msg)
#define logln(msg) Serial.println(msg)
#else
#define log(msg)
#define logln(msg)
#endif

#define OK 1
#define NOTOK 2
#define TIMEOUT 3

#define A6_CMD_TIMEOUT 2000

/////////////////////////////////////////////
// Public methods.
//

A6::A6(int transmitPin, int receivePin) {
    A6conn = new SoftwareSerial(receivePin, transmitPin, false, 1024);
    A6conn->setTimeout(100);
}

A6::~A6() {
    delete A6conn;
}

// Initialize the software serial connection and change the baud rate from the
// default (autodetected) to the desired speed.
void A6::begin(long baudRate) {
    // Give the module some time to settle.
    logln("Waiting for the module to initialize...");
    delay(12000);
    logln("Done.");

    A6conn->flush();

    setRate(baudRate);

    // Factory reset.
    A6command("AT&F", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Echo off.
    A6command("ATE0", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set caller ID on.
    A6command("AT+CLIP=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set SMS to text mode.
    A6command("AT+CMGF=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Switch audio to headset.
    enableSpeaker(0);
}

// Reboot the module by setting the specified pin HIGH, then LOW. The pin should
// be connected to a P-MOSFET, not the A6's POWER pin.
void A6::powerCycle(int pin) {
    logln("Power-cycling module...");

    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);

    delay(1000);

    digitalWrite(pin, HIGH);

    // Give the module some time to settle.
    logln("Power-cycle done.");

    A6conn->flush();
}

// Dial a number.
void A6::dial(String number) {
    char buffer[50];

    logln("Dialing number...");

    sprintf(buffer, "ATD%s;", number.c_str());
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Redial the last number.
void A6::redial() {
    logln("Redialing last number...");
    A6command("AT+DLST", "OK", "CONNECT", A6_CMD_TIMEOUT, 2, NULL);
}

// Answer a call.
void A6::answer() {
    A6command("ATA", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Hang up the phone.
void A6::hangUp() {
    A6command("ATH", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Check whether there is an active call.
callInfo A6::checkCallStatus() {
    char number[50];
    String response = "";
    int respStart = 0, matched = 0;
    callInfo cinfo = (const struct callInfo){ 0 };

    // Issue the command and wait for the response.
    A6command("AT+CLCC", "OK", "+CLCC", A6_CMD_TIMEOUT, 2, &response);

    // Parse the response if it contains a valid +CLCC.
    respStart = response.indexOf("+CLCC");
    if (respStart >= 0) {
        matched = sscanf(response.substring(respStart).c_str(), "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", &cinfo.index, &cinfo.direction, &cinfo.state, &cinfo.mode, &cinfo.multiparty, number, &cinfo.type);
        cinfo.number = String(number);
    }

    return cinfo;
}

// Send an SMS.
byte A6::sendSMS(String number, String text) {
    char ctrlZ[2] = { 0x1a, 0x00 };
    char buffer[100];

    if (text.length() > 159) {
        // We can't send messages longer than 160 characters.
        return NOTOK;
    }

    log("Sending SMS to ");
    log(number);
    logln("...");

    sprintf(buffer, "AT+CMGS=\"%s\"", number.c_str());
    A6command(buffer, ">", "yy", A6_CMD_TIMEOUT, 2, NULL);
    delay(100);
    A6conn->println(text.c_str());
    A6conn->println(ctrlZ);
    A6conn->println();

    return OK;
}

// Set the volume for the speaker. level should be a number between 5 and
// 8 inclusive.
void A6::setVol(byte level) {
    char buffer[30];

    // level should be between 5 and 8.
    level = min(max(level, 5), 8);
    sprintf(buffer, "AT+CLVL=%d", level);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Enable the speaker, rather than the headphones. Pass 0 to route audio through
// headphones, 1 through speaker.
void A6::enableSpeaker(byte enable) {
    char buffer[30];

    // enable should be between 0 and 1.
    enable = min(max(enable, 0), 1);
    sprintf(buffer, "AT+SNFS=%d", enable);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

/////////////////////////////////////////////
// Private methods.
//

// Autodetect the connection rate.
int A6::detectRate() {
    int rate = 0;

    // Try to autodetect the rate.
    logln("Autodetecting connection rate...");
    for (int i = 0; i < 8; i++) {
        switch (i) {
        case 0:
            // Try the usual rate first, to speed things up.
            rate = 9600;
            break;
        case 1:
            rate = 1200;
            break;
        case 2:
            rate = 2400;
            break;
        case 3:
            rate = 4800;
            break;
        case 4:
            rate = 19200;
            break;
        case 5:
            rate = 38400;
            break;
        case 6:
            rate = 57600;
            break;
        case 7:
            rate = 115200;
            break;
        }

        A6conn->begin(rate);
        log("Trying rate ");
        log(rate);
        logln("...");

        delay(100);
        if (A6command("AT", "OK", "OK", 2000, 2, NULL) == OK) {
            return rate;
        }
    }

    // Return a default rate.
    return 9600;
}

// Set the A6 baud rate.
void A6::setRate(long baudRate) {
    int rate = detectRate();

    // The rate is already the desired rate, return.
    if (rate == baudRate) return;

    logln("Discovering baud rate...");
    // Change the rate to the requested.
    char buffer[30];
    sprintf(buffer, "AT+IPR=%d", baudRate);
    A6command(buffer, "OK", "+IPR=", A6_CMD_TIMEOUT, 3, NULL);

    logln("Switching to the new rate...");
    // Begin the connection again at the requested rate.
    A6conn->begin(baudRate);
    logln("Rate set.");
}

// Read some data from the A6 in a non-blocking manner.
String A6::read() {
    String reply = "";
    if (A6conn->available()) reply = A6conn->readString();
    return reply;
}

// Issue a command.
byte A6::A6command(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response) {
    byte returnValue = NOTOK;
    byte count = 0;

    // Get rid of any buffered output.
    A6conn->flush();

    while (count < repetitions && returnValue != OK) {
        log("Issuing command: ");
        logln(command);

        A6conn->print(command);
        A6conn->print("\r");

        if (A6waitFor(resp1, resp2, timeout, response) == OK) {
            returnValue = OK;
        } else {
            returnValue = NOTOK;
        }
        count++;
    }
    return returnValue;
}

// Wait for responses.
byte A6::A6waitFor(const char *resp1, const char *resp2, int timeout, String *response) {
    unsigned long entry = millis();
    int count = 0;
    String reply = "";
    byte retVal = 99;
    do {
        reply += read();
        yield();
    } while ((reply.indexOf(resp1) + reply.indexOf(resp2) == -2) && millis() - entry < timeout);

    if (reply != "") {
        log("Reply in ");
        log((millis() - entry));
        log(" ms: ");
        logln(reply);
    }

    if (response != NULL) *response = reply;

    if ((millis() - entry) >= timeout) {
        retVal = TIMEOUT;
        logln("Timed out.");
    } else {
        if (reply.indexOf(resp1) + reply.indexOf(resp2) > -2) {
            logln("Reply OK.");
            retVal = OK;
        } else {
            logln("Reply NOT OK.");
            retVal = NOTOK;
        }
    }
    return retVal;
}
<|endoftext|>


<commit_before>/**
* @file area.cpp
* @brief programa que Calcula Areas de figuras geometricas
* @author Wanderson A. de Oliveira
* @date 09/03/2017
*/

#include<iostream>
#include"area.h"
#define PI 3.14

using namespace std;

/**
* @brief Funcao que Calcula Area do Triangulo
* @param medida da base do Triangulo
* @param medida da altura do Triangulo
* @return area do Triangulo
*/

float AreaTriangulo(float base, float altura){
   float area;
   area = (base * altura)/2;
   return area;
}

/**
* @brief Funcao que Calcula Area do Retangulo
* @param medida da base do Retangulo
* @param medida da altura do Retangulo
* @return area do Retangulo
*/

float AreaRetangulo(float base, float altura){
   float area;
   area = base * altura;
   return area;
}

/**
* @brief Funcao que Calcula Area do Quadrado
* @param medida do lado do Quadrado
* @return area do Quadrado
*/

float AreaQuadrado(float lado){
   float area;
   area = lado * lado;
   return area;
}

/**
* @brief Funcao que Calcula Area do Circulo
* @param medida do raio do Circulo
* @return area do Circulo
*/

float AreaCirculo(float raio){
   float area;
   area = PI * raio * raio;
   return area;
}

/**
* @brief Funcao que Calcula Area da Piramide
* @param medida da area da base da Piramide
* @param medida da area lateral da Piramide
* @return area da Piramide
*/

float AreaPiramide(float ab, float al){
   float area;
   area = ab + al;
   return area;
}

/**
* @brief Funcao que Calcula Area do Cubo
* @param medida da aresta do Cubo
* @return area do Cubo
*/

float AreaCubo(float aresta){
   float area;
   area = 6 * aresta * aresta;
   return area;
}

/**
* @brief Funcao que Calcula Area do Paralelepipedo
* @param medida da aresta do Paralelepipedo
* @return area do Paralelepipedo
*/

float AreaParalelepipedo(float aresta1, float aresta2, float aresta3){
   float area;
   area = (2 * aresta1 * aresta2) +
	  (2 * aresta1 * aresta3) +
          (2 * aresta2 * aresta3);
   return area;
}

/**
* @brief Funcao que Calcula Area da Esfera
* @param medida do raio da Esfera
* @return area da Esfera
*/

float AreaEsfera(float raio){
   float area;
   area = 4 * PI * raio * raio;
   return area;
}
<commit_msg>Update area.cpp<commit_after>/**
* @file area.cpp
* @brief programa que Calcula Areas de figuras geometricas
* @author Wanderson A. de Oliveira
*/

#include<iostream>
#include"area.h"
#define PI 3.14

using namespace std;

/**
* @brief Funcao que Calcula Area do Triangulo
* @param medida da base do Triangulo
* @param medida da altura do Triangulo
* @return area do Triangulo
*/

float AreaTriangulo(float base, float altura){
   float area;
   area = (base * altura)/2;
   return area;
}

/**
* @brief Funcao que Calcula Area do Retangulo
* @param medida da base do Retangulo
* @param medida da altura do Retangulo
* @return area do Retangulo
*/

float AreaRetangulo(float base, float altura){
   float area;
   area = base * altura;
   return area;
}

/**
* @brief Funcao que Calcula Area do Quadrado
* @param medida do lado do Quadrado
* @return area do Quadrado
*/

float AreaQuadrado(float lado){
   float area;
   area = lado * lado;
   return area;
}

/**
* @brief Funcao que Calcula Area do Circulo
* @param medida do raio do Circulo
* @return area do Circulo
*/

float AreaCirculo(float raio){
   float area;
   area = PI * raio * raio;
   return area;
}

/**
* @brief Funcao que Calcula Area da Piramide
* @param medida da area da base da Piramide
* @param medida da area lateral da Piramide
* @return area da Piramide
*/

float AreaPiramide(float ab, float al){
   float area;
   area = ab + al;
   return area;
}

/**
* @brief Funcao que Calcula Area do Cubo
* @param medida da aresta do Cubo
* @return area do Cubo
*/

float AreaCubo(float aresta){
   float area;
   area = 6 * aresta * aresta;
   return area;
}

/**
* @brief Funcao que Calcula Area do Paralelepipedo
* @param medida da aresta do Paralelepipedo
* @return area do Paralelepipedo
*/

float AreaParalelepipedo(float aresta1, float aresta2, float aresta3){
   float area;
   area = (2 * aresta1 * aresta2) +
	  (2 * aresta1 * aresta3) +
          (2 * aresta2 * aresta3);
   return area;
}

/**
* @brief Funcao que Calcula Area da Esfera
* @param medida do raio da Esfera
* @return area da Esfera
*/

float AreaEsfera(float raio){
   float area;
   area = 4 * PI * raio * raio;
   return area;
}
<|endoftext|>


<commit_before>#include "render_utility.h"
#include "Snapshoot.h"

#include "dataset/AbstractBV.h"
#include "dataset/Image.h"
#include "dataset/ImageSprite.h"
#include "view/MultiSpritesImpl.h"

#include <gl/glew.h>

namespace d2d
{

ISprite* draw_all_to_one_spr(const MultiSpritesImpl* sprites_impl, ISprite* except)
{
	std::vector<ISprite*> sprites;
	sprites_impl->TraverseSprites(FetchAllVisitor<ISprite>(sprites));
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		if (sprites[i] == except) {
			sprites.erase(sprites.begin() + i);
			break;
		}
	}

	return draw_all_to_one_spr(sprites);
}

ISprite* draw_all_to_one_spr(const std::vector<ISprite*>& sprites)
{
	if (sprites.empty()) {
		return NULL;
	}

	Rect r;
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		std::vector<Vector> bound;
		sprites[i]->GetBounding()->getBoundPos(bound);
		for (int j = 0; j < bound.size(); ++j) {
			r.combine(bound[j]);
		}
	}

	float dx = r.xCenter(),
		dy = r.yCenter();
	Snapshoot ss(r.xLength(), r.yLength());
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		ss.DrawSprite(sprites[i], false, dx, dy);
	}

	Image* img = new Image(ss.GetFBO());
	ImageSymbol* symbol = new ImageSymbol(img, "ss");
	ImageSprite* spr = new ImageSprite(symbol);

	spr->SetMirror(false, true);
	spr->SetTransform(Vector(dx, dy), 0);

	return spr;
}

void gl_debug()
{
	GLenum error = glGetError();
	if (error != GL_NO_ERROR
		//		&& error != GL_INVALID_ENUM
		//		&& error != GL_INVALID_VALUE
		//		&& error != GL_INVALID_OPERATION
		//		&& error != GL_OUT_OF_MEMORY
		//		&& error != GL_STACK_OVERFLOW
		//		&& error != GL_STACK_UNDERFLOW
		) {
			int zz = 0;
			exit(1);
	}
}

}<commit_msg>[FIXED] gl debug<commit_after>#include "render_utility.h"
#include "Snapshoot.h"

#include "dataset/AbstractBV.h"
#include "dataset/Image.h"
#include "dataset/ImageSprite.h"
#include "view/MultiSpritesImpl.h"

#include <gl/glew.h>

namespace d2d
{

ISprite* draw_all_to_one_spr(const MultiSpritesImpl* sprites_impl, ISprite* except)
{
	std::vector<ISprite*> sprites;
	sprites_impl->TraverseSprites(FetchAllVisitor<ISprite>(sprites));
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		if (sprites[i] == except) {
			sprites.erase(sprites.begin() + i);
			break;
		}
	}

	return draw_all_to_one_spr(sprites);
}

ISprite* draw_all_to_one_spr(const std::vector<ISprite*>& sprites)
{
	if (sprites.empty()) {
		return NULL;
	}

	Rect r;
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		std::vector<Vector> bound;
		sprites[i]->GetBounding()->getBoundPos(bound);
		for (int j = 0; j < bound.size(); ++j) {
			r.combine(bound[j]);
		}
	}

	float dx = r.xCenter(),
		dy = r.yCenter();
	Snapshoot ss(r.xLength(), r.yLength());
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		ss.DrawSprite(sprites[i], false, dx, dy);
	}

	Image* img = new Image(ss.GetFBO());
	ImageSymbol* symbol = new ImageSymbol(img, "ss");
	ImageSprite* spr = new ImageSprite(symbol);

	spr->SetMirror(false, true);
	spr->SetTransform(Vector(dx, dy), 0);

	return spr;
}

void gl_debug()
{
	GLenum err;
	while ( ( err = glGetError() ) != GL_NO_ERROR) {
		int zz = err;
		std::cerr << err;
	}
}

}<|endoftext|>


<commit_before>/******************************************************************************\
* File:          file.cpp
* Purpose:       Implementation of wxWidgets file extension classes
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/stdpaths.h> // strangely enough, for wxTheFileIconsTable
#include <wx/generic/dirctrlg.h> // for wxTheFileIconsTable
#include <wx/extension/file.h>
#include <wx/extension/app.h> // for wxExApp

wxExFile::wxExFile()
  : m_FileName()
  , m_Stat()
{
}

wxExFile::wxExFile(const wxString& filename, wxFile::OpenMode mode)
  : wxFile(filename, mode)
  , m_FileName(filename)
  , m_Stat(filename)
{
  MakeAbsolute();
}

bool wxExFile::CheckFileSync()
{
  if (IsOpened() ||
     !m_FileName.GetStat().IsOk() ||
     !wxExApp::GetConfigBool("AllowSync", true))
  {
    return false;
  }

  m_FileName.GetStat().Sync();

  if (m_FileName.GetStat().st_mtime != m_Stat.st_mtime)
  {

    FileSync();

    // Next time no sync.
    return m_Stat.Sync();
  }
  else
  {
    return false;
  }
}

void wxExFile::FileNew(const wxExFileName& filename)
{
  m_FileName = filename;

  // Do not make it absolute, the specified filename does not need
  // to exist.
}

bool wxExFile::FileLoad(const wxExFileName& filename)
{
  // First set the member, even if filename does not exist.
  m_FileName = filename;

  if (!m_FileName.FileExists()) return false;

  if (MakeAbsolute())
  {
    if (Open(m_FileName.GetFullPath()))
    {
      DoFileLoad();
      Close();
      return true;
    }
  }

  return false;
}

bool wxExFile::FileSave(const wxString filename)
{
  if (!filename.empty())
  {
    m_FileName.Assign(filename);
    m_FileName.SetLexer();
  }

  if (!Open(m_FileName.GetFullPath(), wxFile::write))
  {
    return false;
  }

  DoFileSave();
  MakeAbsolute();

  Close();

  return true;
}

void wxExFile::FileSync()
{
  if (Open(m_FileName.GetFullPath()))
  {
    DoFileLoad(true);
    Close();
  }
}

bool wxExFile::MakeAbsolute()
{
  if (m_FileName.MakeAbsolute())
  {
    return
      m_FileName.GetStat().Sync(m_FileName.GetFullPath()) &&
      m_Stat.Sync(m_FileName.GetFullPath());
  }
  else
  {
    return false;
  }
}

const wxCharBuffer wxExFile::Read(wxFileOffset seek_position)
{
  const wxFileOffset bytes_to_read = Length() - seek_position;

  // Always do a seek, so you can do more Reads on the same object.
  Seek(seek_position);

  wxCharBuffer buffer(bytes_to_read);

  if (wxFile::Read(buffer.data(), bytes_to_read) != bytes_to_read)
  {
    wxFAIL;
  }

  return buffer;
}

int wxExFileName::GetIconID() const
{
  if (m_Stat.IsOk())
  {
    if (DirExists(GetFullPath()))
    {
      return wxFileIconsTable::folder;
    }
    else if (!GetExt().empty())
    {
      return wxTheFileIconsTable->GetIconID(GetExt());
    }
    else
    {
      return wxFileIconsTable::file;
    }
  }
  else
  {
    return wxFileIconsTable::computer;
  }
}

void wxExFileName::SetLexer(
  const wxString& lexer,
  const wxString& text)
{
  if (wxExApp::GetLexers() == NULL)
  {
    m_Lexer = wxExLexer();
  }
  else
  {
    if (lexer.empty())
    {
      if (text != "forced")
      {
        m_Lexer = wxExApp::GetLexers()->FindByFileName(*this);

        if (m_Lexer.GetScintillaLexer().empty() && !text.empty())
        {
          m_Lexer = wxExApp::GetLexers()->FindByText(text);
        }
      }
      else
      {
        m_Lexer = wxExLexer();
      }
    }
    else
    {
      m_Lexer = wxExApp::GetLexers()->FindByName(lexer);
    }
  }
}

const wxString wxExStat::GetModificationTime(const wxString& format) const
{
  return wxDateTime(st_mtime).Format(format);
}

bool wxExStat::Sync()
{
#ifdef __WXGTK__
  m_IsOk = (::stat(m_FullPath.c_str(), this) != -1);
#else
  m_IsOk = (stat(m_FullPath.c_str(), this) != -1);
#endif
  return m_IsOk;
}

bool wxExStat::Sync(const wxString& fullpath)
{
  m_FullPath = fullpath;
  return Sync();
}
<commit_msg>updated CheckFileSync<commit_after>/******************************************************************************\
* File:          file.cpp
* Purpose:       Implementation of wxWidgets file extension classes
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/stdpaths.h> // strangely enough, for wxTheFileIconsTable
#include <wx/generic/dirctrlg.h> // for wxTheFileIconsTable
#include <wx/extension/file.h>
#include <wx/extension/app.h> // for wxExApp

wxExFile::wxExFile()
  : m_FileName()
  , m_Stat()
{
}

wxExFile::wxExFile(const wxString& filename, wxFile::OpenMode mode)
  : wxFile(filename, mode)
  , m_FileName(filename)
  , m_Stat(filename)
{
  MakeAbsolute();
}

bool wxExFile::CheckFileSync()
{
  if (IsOpened() ||
     !m_FileName.GetStat().IsOk() ||
     !wxExApp::GetConfigBool("AllowSync", true))
  {
    return false;
  }

  if (m_FileName.GetStat().Sync())
  {
    if (m_FileName.GetStat().st_mtime != m_Stat.st_mtime)
    {
      FileSync();

      // Update the stat member, so next time no sync.
      m_Stat.Sync();

      // Now we synced, so always return true.
      return true;
    }
  }

  return false;
}

void wxExFile::FileNew(const wxExFileName& filename)
{
  m_FileName = filename;

  // Do not make it absolute, the specified filename does not need
  // to exist.
}

bool wxExFile::FileLoad(const wxExFileName& filename)
{
  // First set the member, even if filename does not exist.
  m_FileName = filename;

  if (!m_FileName.FileExists()) return false;

  if (MakeAbsolute())
  {
    if (Open(m_FileName.GetFullPath()))
    {
      DoFileLoad();
      Close();
      return true;
    }
  }

  return false;
}

bool wxExFile::FileSave(const wxString filename)
{
  if (!filename.empty())
  {
    m_FileName.Assign(filename);
    m_FileName.SetLexer();
  }

  if (!Open(m_FileName.GetFullPath(), wxFile::write))
  {
    return false;
  }

  DoFileSave();
  MakeAbsolute();

  Close();

  return true;
}

void wxExFile::FileSync()
{
  if (Open(m_FileName.GetFullPath()))
  {
    DoFileLoad(true);
    Close();
  }
}

bool wxExFile::MakeAbsolute()
{
  if (m_FileName.MakeAbsolute())
  {
    return
      m_FileName.GetStat().Sync(m_FileName.GetFullPath()) &&
      m_Stat.Sync(m_FileName.GetFullPath());
  }
  else
  {
    return false;
  }
}

const wxCharBuffer wxExFile::Read(wxFileOffset seek_position)
{
  const wxFileOffset bytes_to_read = Length() - seek_position;

  // Always do a seek, so you can do more Reads on the same object.
  Seek(seek_position);

  wxCharBuffer buffer(bytes_to_read);

  if (wxFile::Read(buffer.data(), bytes_to_read) != bytes_to_read)
  {
    wxFAIL;
  }

  return buffer;
}

int wxExFileName::GetIconID() const
{
  if (m_Stat.IsOk())
  {
    if (DirExists(GetFullPath()))
    {
      return wxFileIconsTable::folder;
    }
    else if (!GetExt().empty())
    {
      return wxTheFileIconsTable->GetIconID(GetExt());
    }
    else
    {
      return wxFileIconsTable::file;
    }
  }
  else
  {
    return wxFileIconsTable::computer;
  }
}

void wxExFileName::SetLexer(
  const wxString& lexer,
  const wxString& text)
{
  if (wxExApp::GetLexers() == NULL)
  {
    m_Lexer = wxExLexer();
  }
  else
  {
    if (lexer.empty())
    {
      if (text != "forced")
      {
        m_Lexer = wxExApp::GetLexers()->FindByFileName(*this);

        if (m_Lexer.GetScintillaLexer().empty() && !text.empty())
        {
          m_Lexer = wxExApp::GetLexers()->FindByText(text);
        }
      }
      else
      {
        m_Lexer = wxExLexer();
      }
    }
    else
    {
      m_Lexer = wxExApp::GetLexers()->FindByName(lexer);
    }
  }
}

const wxString wxExStat::GetModificationTime(const wxString& format) const
{
  return wxDateTime(st_mtime).Format(format);
}

bool wxExStat::Sync()
{
#ifdef __WXGTK__
  m_IsOk = (::stat(m_FullPath.c_str(), this) != -1);
#else
  m_IsOk = (stat(m_FullPath.c_str(), this) != -1);
#endif
  return m_IsOk;
}

bool wxExStat::Sync(const wxString& fullpath)
{
  m_FullPath = fullpath;
  return Sync();
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "SettingsUI.h"
#include "General.h"
#include "afxdialogex.h"

#include "Settings.h"
#include "SkinInfo.h"

#define KEY_NAME L"3RVX"
#define STARTUP_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"

IMPLEMENT_DYNAMIC(General, CPropertyPage)

General::General() :
CPropertyPage(General::IDD) {

}

General::~General() {

}

void General::DoDataExchange(CDataExchange* pDX)
{
    CPropertyPage::DoDataExchange(pDX);
    DDX_Control(pDX, CHK_STARTUP, _startup);
    DDX_Control(pDX, CHK_NOTIFY, _notify);
    DDX_Control(pDX, CHK_SOUNDS, _sounds);
    DDX_Control(pDX, CMB_LANG, _lang);
    DDX_Control(pDX, GRP_SKIN, _skinGrp);
    DDX_Control(pDX, GRP_BEHAVIOR, _behaviorGrp);
    DDX_Control(pDX, GRP_LANGUAGE, _languageGrp);
    DDX_Control(pDX, LBL_AUTHOR, _author);
    DDX_Control(pDX, CMB_SKIN, _skins);
    DDX_Control(pDX, BTN_WEBSITE, _website);
}

BOOL General::OnApply() {
    Settings *settings = Settings::Instance();
    RunOnStartup(CHECKED(_startup));
    settings->NotifyIconEnabled(CHECKED(_notify));
    settings->SoundEffectsEnabled(CHECKED(_sounds));

    int skinIdx = _skins.GetCurSel();
    CString skinName;
    _skins.GetLBText(skinIdx, skinName);
    settings->CurrentSkin((LPCWSTR) skinName);

    int result = settings->Save();
    OutputDebugString(std::to_wstring(result).c_str());
    return CPropertyPage::OnApply();
}

BOOL General::OnCommand(WPARAM wParam, LPARAM lParam) {
    SetModified();
    return CPropertyPage::OnCommand(wParam, lParam);
}

void General::LoadSettings() {
    Settings *settings = Settings::Instance();
    _startup.SetCheck(RunOnStartup());
    _notify.SetCheck(settings->NotifyIconEnabled());
    _sounds.SetCheck(settings->SoundEffectsEnabled());

    /* Determine which skins are available */
    std::list<CString> skins = FindSkins(L"../3RVX/Skins");
    for (CString skin : skins) {
        _skins.AddString(skin);
    }

    /* Update the combo box with the current skin */
    std::wstring current = settings->SkinName();
    int idx = _skins.SelectString(0, current.c_str());
    if (idx == CB_ERR) {
        _skins.SelectString(0, DEFAULT_SKIN);
    }
    LoadSkinInfo();

    /* Populate the language box */
    std::list<CString> languages = FindLanguages(
        settings->LanguagesDir().c_str());

    for (CString language : languages) {
        _lang.AddString(language);
    }
    std::wstring currentLang = settings->LanguageName();
    _lang.SelectString(0, currentLang.c_str());
}

BOOL General::OnInitDialog() {
    CPropertyPage::OnInitDialog();
    LoadSettings();
    return TRUE;
}

std::list<CString> General::FindSkins(CString dir) {
    std::list<CString> skins;

    CFileFind ff;
    dir += L"\\*";
    BOOL result = ff.FindFile(dir);
    while (result) {
        result = ff.FindNextFile();
        if (ff.IsDots()) {
            continue;
        }

        if (ff.IsDirectory()) {
            CFileFind inDir;
            CString dirPath = ff.GetFilePath();
            dirPath += L"\\skin.xml";
            if (inDir.FindFile(dirPath)) {
                /* We found a skin XML file; add the skin dir to our list. */
                skins.push_back(ff.GetFileName());
            }
        }
    }

    return skins;
}

std::list<CString> General::FindLanguages(CString dir) {
    std::list<CString> languages;

    CFileFind ff;
    dir += L"\\*.xml";
    BOOL result = ff.FindFile(dir);
    while (result) {
        result = ff.FindNextFile();
        if (ff.IsDots() || ff.IsDirectory()) {
            continue;
        }

        /* Even though we asked for *xml files, FindNextFile() will still
         * return results that start with .xml (like .xmlblah) */
        CString ext = ff.GetFileName().Right(3);
        if (ext == L"xml") {
            languages.push_back(ff.GetFileTitle());
        }
    }

    return languages;
}

void General::LoadSkinInfo() {
    CString selectedSkin;
    int selIdx = _skins.GetCurSel();
    _skins.GetLBText(selIdx, selectedSkin);

    std::wstring skinXML
        = Settings::Instance()->SkinXML((LPCWSTR) selectedSkin);
    SkinInfo s(skinXML);

    CString authorText(L"Author:");
    authorText.Append(L" ");
    authorText.Append(s.Author().c_str());
    _author.SetWindowTextW(authorText);

    _url = s.URL();
    _website.EnableWindow((_url != L""));
}
bool General::RunOnStartup() {
    CRegKey rk;
    int result = rk.Open(HKEY_CURRENT_USER, STARTUP_KEY, KEY_READ);
    if (result == ERROR_SUCCESS) {
        CString str;
        ULONG bufLen = 1024;
        LPTSTR buf = str.GetBufferSetLength(bufLen);

        int queryResult = rk.QueryStringValue(KEY_NAME, buf, &bufLen);
        if (queryResult == ERROR_SUCCESS) {
            return true;
        }
    }
    return false;
}

void General::RunOnStartup(bool enable) {
    std::wstring path = Settings::AppDir();
    CString exePath(path.c_str());
    exePath.Append(L"\\3RVX.exe");

    CRegKey rk;
    int result = rk.Open(HKEY_CURRENT_USER, STARTUP_KEY, KEY_WRITE);
    if (result == ERROR_SUCCESS) {
        if (enable) {
            rk.SetStringValue(KEY_NAME, exePath, REG_SZ);
        } else {
            rk.DeleteValue(KEY_NAME);
        }
    }
}

BEGIN_MESSAGE_MAP(General, CPropertyPage)
    ON_BN_CLICKED(BTN_WEBSITE, &General::OnBnClickedWebsite)
    ON_CBN_SELCHANGE(CMB_SKIN, &General::OnCbnSelchangeSkin)
END_MESSAGE_MAP()

void General::OnBnClickedWebsite() {
    ShellExecute(NULL, L"open", _url.c_str(), NULL, NULL, SW_SHOWNORMAL);
}

void General::OnCbnSelchangeSkin() {
    LoadSkinInfo();
}<commit_msg>Move settings save to display tab (this needs to be on the last tab)<commit_after>#include "stdafx.h"
#include "SettingsUI.h"
#include "General.h"
#include "afxdialogex.h"

#include "Settings.h"
#include "SkinInfo.h"

#define KEY_NAME L"3RVX"
#define STARTUP_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"

IMPLEMENT_DYNAMIC(General, CPropertyPage)

General::General() :
CPropertyPage(General::IDD) {

}

General::~General() {

}

void General::DoDataExchange(CDataExchange* pDX)
{
    CPropertyPage::DoDataExchange(pDX);
    DDX_Control(pDX, CHK_STARTUP, _startup);
    DDX_Control(pDX, CHK_NOTIFY, _notify);
    DDX_Control(pDX, CHK_SOUNDS, _sounds);
    DDX_Control(pDX, CMB_LANG, _lang);
    DDX_Control(pDX, GRP_SKIN, _skinGrp);
    DDX_Control(pDX, GRP_BEHAVIOR, _behaviorGrp);
    DDX_Control(pDX, GRP_LANGUAGE, _languageGrp);
    DDX_Control(pDX, LBL_AUTHOR, _author);
    DDX_Control(pDX, CMB_SKIN, _skins);
    DDX_Control(pDX, BTN_WEBSITE, _website);
}

BOOL General::OnApply() {
    Settings *settings = Settings::Instance();
    RunOnStartup(CHECKED(_startup));
    settings->NotifyIconEnabled(CHECKED(_notify));
    settings->SoundEffectsEnabled(CHECKED(_sounds));

    int skinIdx = _skins.GetCurSel();
    CString skinName;
    _skins.GetLBText(skinIdx, skinName);
    settings->CurrentSkin((LPCWSTR) skinName);

    return CPropertyPage::OnApply();
}

BOOL General::OnCommand(WPARAM wParam, LPARAM lParam) {
    SetModified();
    return CPropertyPage::OnCommand(wParam, lParam);
}

void General::LoadSettings() {
    Settings *settings = Settings::Instance();
    _startup.SetCheck(RunOnStartup());
    _notify.SetCheck(settings->NotifyIconEnabled());
    _sounds.SetCheck(settings->SoundEffectsEnabled());

    /* Determine which skins are available */
    std::list<CString> skins = FindSkins(L"../3RVX/Skins");
    for (CString skin : skins) {
        _skins.AddString(skin);
    }

    /* Update the combo box with the current skin */
    std::wstring current = settings->SkinName();
    int idx = _skins.SelectString(0, current.c_str());
    if (idx == CB_ERR) {
        _skins.SelectString(0, DEFAULT_SKIN);
    }
    LoadSkinInfo();

    /* Populate the language box */
    std::list<CString> languages = FindLanguages(
        settings->LanguagesDir().c_str());

    for (CString language : languages) {
        _lang.AddString(language);
    }
    std::wstring currentLang = settings->LanguageName();
    _lang.SelectString(0, currentLang.c_str());
}

BOOL General::OnInitDialog() {
    CPropertyPage::OnInitDialog();
    LoadSettings();
    return TRUE;
}

std::list<CString> General::FindSkins(CString dir) {
    std::list<CString> skins;

    CFileFind ff;
    dir += L"\\*";
    BOOL result = ff.FindFile(dir);
    while (result) {
        result = ff.FindNextFile();
        if (ff.IsDots()) {
            continue;
        }

        if (ff.IsDirectory()) {
            CFileFind inDir;
            CString dirPath = ff.GetFilePath();
            dirPath += L"\\skin.xml";
            if (inDir.FindFile(dirPath)) {
                /* We found a skin XML file; add the skin dir to our list. */
                skins.push_back(ff.GetFileName());
            }
        }
    }

    return skins;
}

std::list<CString> General::FindLanguages(CString dir) {
    std::list<CString> languages;

    CFileFind ff;
    dir += L"\\*.xml";
    BOOL result = ff.FindFile(dir);
    while (result) {
        result = ff.FindNextFile();
        if (ff.IsDots() || ff.IsDirectory()) {
            continue;
        }

        /* Even though we asked for *xml files, FindNextFile() will still
         * return results that start with .xml (like .xmlblah) */
        CString ext = ff.GetFileName().Right(3);
        if (ext == L"xml") {
            languages.push_back(ff.GetFileTitle());
        }
    }

    return languages;
}

void General::LoadSkinInfo() {
    CString selectedSkin;
    int selIdx = _skins.GetCurSel();
    _skins.GetLBText(selIdx, selectedSkin);

    std::wstring skinXML
        = Settings::Instance()->SkinXML((LPCWSTR) selectedSkin);
    SkinInfo s(skinXML);

    CString authorText(L"Author:");
    authorText.Append(L" ");
    authorText.Append(s.Author().c_str());
    _author.SetWindowTextW(authorText);

    _url = s.URL();
    _website.EnableWindow((_url != L""));
}
bool General::RunOnStartup() {
    CRegKey rk;
    int result = rk.Open(HKEY_CURRENT_USER, STARTUP_KEY, KEY_READ);
    if (result == ERROR_SUCCESS) {
        CString str;
        ULONG bufLen = 1024;
        LPTSTR buf = str.GetBufferSetLength(bufLen);

        int queryResult = rk.QueryStringValue(KEY_NAME, buf, &bufLen);
        if (queryResult == ERROR_SUCCESS) {
            return true;
        }
    }
    return false;
}

void General::RunOnStartup(bool enable) {
    std::wstring path = Settings::AppDir();
    CString exePath(path.c_str());
    exePath.Append(L"\\3RVX.exe");

    CRegKey rk;
    int result = rk.Open(HKEY_CURRENT_USER, STARTUP_KEY, KEY_WRITE);
    if (result == ERROR_SUCCESS) {
        if (enable) {
            rk.SetStringValue(KEY_NAME, exePath, REG_SZ);
        } else {
            rk.DeleteValue(KEY_NAME);
        }
    }
}

BEGIN_MESSAGE_MAP(General, CPropertyPage)
    ON_BN_CLICKED(BTN_WEBSITE, &General::OnBnClickedWebsite)
    ON_CBN_SELCHANGE(CMB_SKIN, &General::OnCbnSelchangeSkin)
END_MESSAGE_MAP()

void General::OnBnClickedWebsite() {
    ShellExecute(NULL, L"open", _url.c_str(), NULL, NULL, SW_SHOWNORMAL);
}

void General::OnCbnSelchangeSkin() {
    LoadSkinInfo();
}<|endoftext|>